changeset 2503:10692383c103 trunk

[svn] first try for libid3tag integration. this improved libid3tag supports vfs operations and is capable of adding id3v2 tag to files which doesn't have id3v2 tag ever.
author yaz
date Sun, 11 Feb 2007 05:19:07 -0800
parents b7be0af74307
children fcf730269639
files ChangeLog configure.ac src/Makefile src/audacious/build_stamp.c src/libid3tag/Makefile src/libid3tag/compat.c src/libid3tag/compat.gperf src/libid3tag/compat.h src/libid3tag/config.h src/libid3tag/crc.c src/libid3tag/crc.h src/libid3tag/debug.c src/libid3tag/debug.h src/libid3tag/field.c src/libid3tag/field.h src/libid3tag/file.c src/libid3tag/file.h src/libid3tag/frame.c src/libid3tag/frame.h src/libid3tag/frametype.c src/libid3tag/frametype.gperf src/libid3tag/frametype.h src/libid3tag/genre.c src/libid3tag/genre.dat src/libid3tag/genre.dat.in src/libid3tag/genre.dat.sed src/libid3tag/genre.h src/libid3tag/global.h src/libid3tag/id3tag.h src/libid3tag/latin1.c src/libid3tag/latin1.h src/libid3tag/parse.c src/libid3tag/parse.h src/libid3tag/render.c src/libid3tag/render.h src/libid3tag/tag.c src/libid3tag/tag.h src/libid3tag/ucs4.c src/libid3tag/ucs4.h src/libid3tag/utf16.c src/libid3tag/utf16.h src/libid3tag/utf8.c src/libid3tag/utf8.h src/libid3tag/util.c src/libid3tag/util.h src/libid3tag/version.c src/libid3tag/version.h
diffstat 47 files changed, 8990 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Feb 11 01:16:10 2007 -0800
+++ b/ChangeLog	Sun Feb 11 05:19:07 2007 -0800
@@ -1,3 +1,12 @@
+2007-02-11 09:16:10 +0000  William Pitcock <nenolod@sacredspiral.co.uk>
+  revision [4014]
+  - Update Welsh translation:
+    455 strings (0 bad tokens, 0 fuzzy, 0 not translated)
+  
+  trunk/po/cy.po |  420 +++++++++++++++++++++++++++++----------------------------
+  1 file changed, 214 insertions(+), 206 deletions(-)
+
+
 2007-02-11 09:02:12 +0000  William Pitcock <nenolod@sacredspiral.co.uk>
   revision [4012]
   - fix POTFILES.in
--- a/configure.ac	Sun Feb 11 01:16:10 2007 -0800
+++ b/configure.ac	Sun Feb 11 05:19:07 2007 -0800
@@ -94,6 +94,13 @@
     [AC_MSG_ERROR([Cannot find glib2/gtk2/pango])]
 )
 
+dnl Check for GLib
+
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.6.0],
+    [ADD_PC_REQUIRES([glib-2.0 >= 2.6.0])],
+    [AC_MSG_ERROR([Cannot find glib2])]
+)
+
 dnl Check for libglade
 
 PKG_CHECK_MODULES(LIBGLADE, [libglade-2.0 >= 2.3.1],
--- a/src/Makefile	Sun Feb 11 01:16:10 2007 -0800
+++ b/src/Makefile	Sun Feb 11 05:19:07 2007 -0800
@@ -3,7 +3,7 @@
 include ../mk/rules.mk
 include ../mk/init.mk
 
-SUBDIRS = libaudacious $(INTL_OBJECTIVE) $(SUBDIR_GUESS) audacious audtool
+SUBDIRS = libaudacious $(INTL_OBJECTIVE) $(SUBDIR_GUESS) audacious audtool libid3tag
 
 include ../mk/objective.mk
 
--- a/src/audacious/build_stamp.c	Sun Feb 11 01:16:10 2007 -0800
+++ b/src/audacious/build_stamp.c	Sun Feb 11 05:19:07 2007 -0800
@@ -1,2 +1,2 @@
 #include <glib.h>
-const gchar *svn_stamp = "20070211-4012";
+const gchar *svn_stamp = "20070211-4014";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/Makefile	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,37 @@
+include ../../mk/rules.mk
+include ../../mk/init.mk
+
+OBJECTIVE_LIBS = libid3tag.so
+
+LDFLAGS += -Wl,-export-dynamic
+
+LIBADD += $(GLIB_LIBS)
+
+CFLAGS += $(PICFLAGS) \
+	-I.. \
+	$(GLIB_CFLAGS)
+
+HEADERS = id3tag.h
+
+SOURCES = \
+	compat.c \
+	debug.c \
+	file.c \
+	frametype.c \
+	latin1.c \
+	render.c \
+	ucs4.c \
+	utf8.c \
+	version.c \
+	crc.c \
+	field.c \
+	frame.c \
+	genre.c \
+	parse.c \
+	tag.c \
+	utf16.c \
+	util.c
+
+OBJECTS = ${SOURCES:.c=.o}
+
+include ../../mk/objective.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/compat.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,412 @@
+/* C code produced by gperf version 2.7 */
+/* Command-line: gperf -tCcTonD -K id -N id3_compat_lookup -s -3 -k * compat.gperf  */
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * Id: compat.gperf,v 1.11 2004/01/23 09:41:32 rob Exp 
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+# include <string.h>
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include "id3tag.h"
+# include "compat.h"
+# include "frame.h"
+# include "field.h"
+# include "parse.h"
+# include "ucs4.h"
+
+# define EQ(id)    #id, 0
+# define OBSOLETE    0, 0
+# define TX(id)    #id, translate_##id
+
+static id3_compat_func_t translate_TCON;
+
+#define TOTAL_KEYWORDS 73
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 4
+#define MIN_HASH_VALUE 1
+#define MAX_HASH_VALUE 84
+/* maximum key range = 84, duplicates = 10 */
+
+#ifdef __GNUC__
+__inline
+#endif
+static unsigned int
+hash (str, len)
+     register const char *str;
+     register unsigned int len;
+{
+  static const unsigned char asso_values[] =
+    {
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 22,
+      21, 27, 26, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85,  9,  3,  0, 27, 16,
+       6, 30, 85, 15, 85, 22,  2, 15,  4,  1,
+       0, 30, 13, 17, 22,  0, 24,  5, 31, 25,
+      15, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+      85, 85, 85, 85, 85, 85
+    };
+  register int hval = 0;
+
+  switch (len)
+    {
+      default:
+      case 4:
+        hval += asso_values[(unsigned char)str[3]];
+      case 3:
+        hval += asso_values[(unsigned char)str[2]];
+      case 2:
+        hval += asso_values[(unsigned char)str[1]];
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+#ifdef __GNUC__
+__inline
+#endif
+const struct id3_compat *
+id3_compat_lookup (str, len)
+     register const char *str;
+     register unsigned int len;
+{
+  static const struct id3_compat wordlist[] =
+    {
+      {"POP",  EQ(POPM)  /* Popularimeter */},
+      {"WCP",  EQ(WCOP)  /* Copyright/legal information */},
+      {"WPB",  EQ(WPUB)  /* Publishers official webpage */},
+      {"BUF",  EQ(RBUF)  /* Recommended buffer size */},
+      {"PIC",  EQ(APIC)  /* Attached picture */},
+      {"COM",  EQ(COMM)  /* Comments */},
+      {"IPL",  EQ(TIPL)  /* Involved people list */},
+      {"MLL",  EQ(MLLT)  /* MPEG location lookup table */},
+      {"WAF",  EQ(WOAF)  /* Official audio file webpage */},
+      {"WCM",  EQ(WCOM)  /* Commercial information */},
+      {"UFI",  EQ(UFID)  /* Unique file identifier */},
+      {"CRA",  EQ(AENC)  /* Audio encryption */},
+      {"TCO",  TX(TCON)  /* Content type */},
+      {"ULT",  EQ(USLT)  /* Unsynchronised lyric/text transcription */},
+      {"TOL",  EQ(TOLY)  /* Original lyricist(s)/text writer(s) */},
+      {"TBP",  EQ(TBPM)  /* BPM (beats per minute) */},
+      {"TPB",  EQ(TPUB)  /* Publisher */},
+      {"CNT",  EQ(PCNT)  /* Play counter */},
+      {"TCON", TX(TCON)  /* Content type */},
+      {"WAR",  EQ(WOAR)  /* Official artist/performer webpage */},
+      {"LNK",  EQ(LINK)  /* Linked information */},
+      {"CRM",  OBSOLETE  /* Encrypted meta frame [obsolete] */},
+      {"TOF",  EQ(TOFN)  /* Original filename */},
+      {"MCI",  EQ(MCDI)  /* Music CD identifier */},
+      {"TPA",  EQ(TPOS)  /* Part of a set */},
+      {"WAS",  EQ(WOAS)  /* Official audio source webpage */},
+      {"TOA",  EQ(TOPE)  /* Original artist(s)/performer(s) */},
+      {"TAL",  EQ(TALB)  /* Album/movie/show title */},
+      {"TLA",  EQ(TLAN)  /* Language(s) */},
+      {"IPLS", EQ(TIPL)  /* Involved people list */},
+      {"TCR",  EQ(TCOP)  /* Copyright message */},
+      {"TRC",  EQ(TSRC)  /* ISRC (international standard recording code) */},
+      {"TOR",  EQ(TDOR)  /* Original release year [obsolete] */},
+      {"TCM",  EQ(TCOM)  /* Composer */},
+      {"ETC",  EQ(ETCO)  /* Event timing codes */},
+      {"STC",  EQ(SYTC)  /* Synchronised tempo codes */},
+      {"TLE",  EQ(TLEN)  /* Length */},
+      {"SLT",  EQ(SYLT)  /* Synchronised lyric/text */},
+      {"TEN",  EQ(TENC)  /* Encoded by */},
+      {"TP2",  EQ(TPE2)  /* Band/orchestra/accompaniment */},
+      {"TP1",  EQ(TPE1)  /* Lead performer(s)/soloist(s) */},
+      {"TOT",  EQ(TOAL)  /* Original album/movie/show title */},
+      {"EQU",  OBSOLETE  /* Equalization [obsolete] */},
+      {"RVA",  OBSOLETE  /* Relative volume adjustment [obsolete] */},
+      {"GEO",  EQ(GEOB)  /* General encapsulated object */},
+      {"TP4",  EQ(TPE4)  /* Interpreted, remixed, or otherwise modified by */},
+      {"TP3",  EQ(TPE3)  /* Conductor/performer refinement */},
+      {"TFT",  EQ(TFLT)  /* File type */},
+      {"TIM",  OBSOLETE  /* Time [obsolete] */},
+      {"REV",  EQ(RVRB)  /* Reverb */},
+      {"TSI",  OBSOLETE  /* Size [obsolete] */},
+      {"EQUA", OBSOLETE  /* Equalization [obsolete] */},
+      {"TSS",  EQ(TSSE)  /* Software/hardware and settings used for encoding */},
+      {"TRK",  EQ(TRCK)  /* Track number/position in set */},
+      {"TDA",  OBSOLETE  /* Date [obsolete] */},
+      {"TMT",  EQ(TMED)  /* Media type */},
+      {"TKE",  EQ(TKEY)  /* Initial key */},
+      {"TORY", EQ(TDOR)  /* Original release year [obsolete] */},
+      {"TRD",  OBSOLETE  /* Recording dates [obsolete] */},
+      {"TYE",  OBSOLETE  /* Year [obsolete] */},
+      {"TT2",  EQ(TIT2)  /* Title/songname/content description */},
+      {"TT1",  EQ(TIT1)  /* Content group description */},
+      {"WXX",  EQ(WXXX)  /* User defined URL link frame */},
+      {"TIME", OBSOLETE  /* Time [obsolete] */},
+      {"TSIZ", OBSOLETE  /* Size [obsolete] */},
+      {"TT3",  EQ(TIT3)  /* Subtitle/description refinement */},
+      {"TRDA", OBSOLETE  /* Recording dates [obsolete] */},
+      {"RVAD", OBSOLETE  /* Relative volume adjustment [obsolete] */},
+      {"TDY",  EQ(TDLY)  /* Playlist delay */},
+      {"TXT",  EQ(TEXT)  /* Lyricist/text writer */},
+      {"TYER", OBSOLETE  /* Year [obsolete] */},
+      {"TDAT", OBSOLETE  /* Date [obsolete] */},
+      {"TXX",  EQ(TXXX)  /* User defined text information frame */}
+    };
+
+  static const short lookup[] =
+    {
+        -1,    0,   -1,  -53,   -2,    1,  -49,   -2,
+         2,    3,   -1,  -46,   -2,  -43,   -2,    4,
+         5,    6,   -1,    7, -163,   10,   11,   12,
+        13, -161,   17, -159,  -77,   22,   23,  -80,
+        26,  -85,   29,  -87,   32,   33,   34,   35,
+        36,   37,   38,   39,   40,   41, -155,   44,
+        45,   46,   47,   -1,   48,   49,   50,   51,
+        52,   53,   54,   55,   56,   57,   58,   59,
+        -1,   60,   61,   62,   63,   64,   -1, -151,
+        -1,   67,   68,   69,   70,   -8,   -2,   -1,
+        71,  -31,   -2,   -1,   72,  -55,   -2,  -59,
+        -3,  -65,   -2
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int index = lookup[key];
+
+          if (index >= 0)
+            {
+              register const char *s = wordlist[index].id;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1))
+                return &wordlist[index];
+            }
+          else if (index < -TOTAL_KEYWORDS)
+            {
+              register int offset = - 1 - TOTAL_KEYWORDS - index;
+              register const struct id3_compat *wordptr = &wordlist[TOTAL_KEYWORDS + lookup[offset]];
+              register const struct id3_compat *wordendptr = wordptr + -lookup[offset + 1];
+
+              while (wordptr < wordendptr)
+                {
+                  register const char *s = wordptr->id;
+
+                  if (*str == *s && !strncmp (str + 1, s + 1, len - 1))
+                    return wordptr;
+                  wordptr++;
+                }
+            }
+        }
+    }
+  return 0;
+}
+
+static
+int translate_TCON(struct id3_frame *frame, char const *oldid,
+		   id3_byte_t const *data, id3_length_t length)
+{
+  id3_byte_t const *end;
+  enum id3_field_textencoding encoding;
+  id3_ucs4_t *string = 0, *ptr, *endptr;
+  int result = 0;
+
+  /* translate old TCON syntax into multiple strings */
+
+  assert(frame->nfields == 2);
+
+  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
+
+  end = data + length;
+
+  if (id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1)
+    goto fail;
+
+  string = id3_parse_string(&data, end - data, encoding, 0);
+  if (string == 0)
+    goto fail;
+
+  ptr = string;
+  while (*ptr == '(') {
+    if (*++ptr == '(')
+      break;
+
+    endptr = ptr;
+    while (*endptr && *endptr != ')')
+      ++endptr;
+
+    if (*endptr)
+      *endptr++ = 0;
+
+    if (id3_field_addstring(&frame->fields[1], ptr) == -1)
+      goto fail;
+
+    ptr = endptr;
+  }
+
+  if (*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1)
+    goto fail;
+
+  if (0) {
+  fail:
+    result = -1;
+  }
+
+  if (string)
+    free(string);
+
+  return result;
+}
+
+/*
+ * NAME:	compat->fixup()
+ * DESCRIPTION:	finish compatibility translations
+ */
+int id3_compat_fixup(struct id3_tag *tag)
+{
+  struct id3_frame *frame;
+  unsigned int index;
+  id3_ucs4_t timestamp[17] = { 0 };
+  int result = 0;
+
+  /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */
+
+  /*
+   * TYE/TYER: YYYY
+   * TDA/TDAT: DDMM
+   * TIM/TIME: HHMM
+   *
+   * TDRC: yyyy-MM-ddTHH:mm
+   */
+
+  index = 0;
+  while ((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) {
+    char const *id;
+    id3_byte_t const *data, *end;
+    id3_length_t length;
+    enum id3_field_textencoding encoding;
+    id3_ucs4_t *string;
+
+    id = id3_field_getframeid(&frame->fields[0]);
+    assert(id);
+
+    if (strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 &&
+	strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 &&
+	strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0)
+      continue;
+
+    data = id3_field_getbinarydata(&frame->fields[1], &length);
+    assert(data);
+
+    if (length < 1)
+      continue;
+
+    end = data + length;
+
+    encoding = id3_parse_uint(&data, 1);
+    string   = id3_parse_string(&data, end - data, encoding, 0);
+
+    if (string == 0)
+      continue;
+
+    if (id3_ucs4_length(string) < 4) {
+      free(string);
+      continue;
+    }
+
+    if (strcmp(id, "TYER") == 0 ||
+	strcmp(id, "YTYE") == 0) {
+      timestamp[0] = string[0];
+      timestamp[1] = string[1];
+      timestamp[2] = string[2];
+      timestamp[3] = string[3];
+    }
+    else if (strcmp(id, "TDAT") == 0 ||
+	     strcmp(id, "YTDA") == 0) {
+      timestamp[4] = '-';
+      timestamp[5] = string[2];
+      timestamp[6] = string[3];
+      timestamp[7] = '-';
+      timestamp[8] = string[0];
+      timestamp[9] = string[1];
+    }
+    else {  /* TIME or YTIM */
+      timestamp[10] = 'T';
+      timestamp[11] = string[0];
+      timestamp[12] = string[1];
+      timestamp[13] = ':';
+      timestamp[14] = string[2];
+      timestamp[15] = string[3];
+    }
+
+    free(string);
+  }
+
+  if (timestamp[0]) {
+    id3_ucs4_t *strings;
+
+    frame = id3_frame_new("TDRC");
+    if (frame == 0)
+      goto fail;
+
+    strings = timestamp;
+
+    if (id3_field_settextencoding(&frame->fields[0],
+				  ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 ||
+	id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 ||
+	id3_tag_attachframe(tag, frame) == -1) {
+      id3_frame_delete(frame);
+      goto fail;
+    }
+  }
+
+  if (0) {
+  fail:
+    result = -1;
+  }
+
+  return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/compat.gperf	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,300 @@
+%{
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: compat.gperf,v 1.11 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+# include <string.h>
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include "id3tag.h"
+# include "compat.h"
+# include "frame.h"
+# include "field.h"
+# include "parse.h"
+# include "ucs4.h"
+
+# define EQ(id)    #id, 0
+# define OBSOLETE    0, 0
+# define TX(id)    #id, translate_##id
+
+static id3_compat_func_t translate_TCON;
+%}
+struct id3_compat;
+%%
+#
+# ID3v2.2 and ID3v2.3 frames
+#
+# Only obsolete frames or frames with an equivalent ID3v2.4 frame ID are
+# listed here. If a frame ID is not listed, it is assumed that the same
+# frame ID is itself the equivalent ID3v2.4 frame ID.
+#
+# This list may also include frames with new content interpretations; the
+# translation function will rewrite the contents to comply with ID3v2.4.
+#
+BUF,  EQ(RBUF)  /* Recommended buffer size */
+CNT,  EQ(PCNT)  /* Play counter */
+COM,  EQ(COMM)  /* Comments */
+CRA,  EQ(AENC)  /* Audio encryption */
+CRM,  OBSOLETE  /* Encrypted meta frame [obsolete] */
+EQU,  OBSOLETE  /* Equalization [obsolete] */
+EQUA, OBSOLETE  /* Equalization [obsolete] */
+ETC,  EQ(ETCO)  /* Event timing codes */
+GEO,  EQ(GEOB)  /* General encapsulated object */
+IPL,  EQ(TIPL)  /* Involved people list */
+IPLS, EQ(TIPL)  /* Involved people list */
+LNK,  EQ(LINK)  /* Linked information */
+MCI,  EQ(MCDI)  /* Music CD identifier */
+MLL,  EQ(MLLT)  /* MPEG location lookup table */
+PIC,  EQ(APIC)  /* Attached picture */
+POP,  EQ(POPM)  /* Popularimeter */
+REV,  EQ(RVRB)  /* Reverb */
+RVA,  OBSOLETE  /* Relative volume adjustment [obsolete] */
+RVAD, OBSOLETE  /* Relative volume adjustment [obsolete] */
+SLT,  EQ(SYLT)  /* Synchronised lyric/text */
+STC,  EQ(SYTC)  /* Synchronised tempo codes */
+TAL,  EQ(TALB)  /* Album/movie/show title */
+TBP,  EQ(TBPM)  /* BPM (beats per minute) */
+TCM,  EQ(TCOM)  /* Composer */
+TCO,  TX(TCON)  /* Content type */
+TCON, TX(TCON)  /* Content type */
+TCR,  EQ(TCOP)  /* Copyright message */
+TDA,  OBSOLETE  /* Date [obsolete] */
+TDAT, OBSOLETE  /* Date [obsolete] */
+TDY,  EQ(TDLY)  /* Playlist delay */
+TEN,  EQ(TENC)  /* Encoded by */
+TFT,  EQ(TFLT)  /* File type */
+TIM,  OBSOLETE  /* Time [obsolete] */
+TIME, OBSOLETE  /* Time [obsolete] */
+TKE,  EQ(TKEY)  /* Initial key */
+TLA,  EQ(TLAN)  /* Language(s) */
+TLE,  EQ(TLEN)  /* Length */
+TMT,  EQ(TMED)  /* Media type */
+TOA,  EQ(TOPE)  /* Original artist(s)/performer(s) */
+TOF,  EQ(TOFN)  /* Original filename */
+TOL,  EQ(TOLY)  /* Original lyricist(s)/text writer(s) */
+TOR,  EQ(TDOR)  /* Original release year [obsolete] */
+TORY, EQ(TDOR)  /* Original release year [obsolete] */
+TOT,  EQ(TOAL)  /* Original album/movie/show title */
+TP1,  EQ(TPE1)  /* Lead performer(s)/soloist(s) */
+TP2,  EQ(TPE2)  /* Band/orchestra/accompaniment */
+TP3,  EQ(TPE3)  /* Conductor/performer refinement */
+TP4,  EQ(TPE4)  /* Interpreted, remixed, or otherwise modified by */
+TPA,  EQ(TPOS)  /* Part of a set */
+TPB,  EQ(TPUB)  /* Publisher */
+TRC,  EQ(TSRC)  /* ISRC (international standard recording code) */
+TRD,  OBSOLETE  /* Recording dates [obsolete] */
+TRDA, OBSOLETE  /* Recording dates [obsolete] */
+TRK,  EQ(TRCK)  /* Track number/position in set */
+TSI,  OBSOLETE  /* Size [obsolete] */
+TSIZ, OBSOLETE  /* Size [obsolete] */
+TSS,  EQ(TSSE)  /* Software/hardware and settings used for encoding */
+TT1,  EQ(TIT1)  /* Content group description */
+TT2,  EQ(TIT2)  /* Title/songname/content description */
+TT3,  EQ(TIT3)  /* Subtitle/description refinement */
+TXT,  EQ(TEXT)  /* Lyricist/text writer */
+TXX,  EQ(TXXX)  /* User defined text information frame */
+TYE,  OBSOLETE  /* Year [obsolete] */
+TYER, OBSOLETE  /* Year [obsolete] */
+UFI,  EQ(UFID)  /* Unique file identifier */
+ULT,  EQ(USLT)  /* Unsynchronised lyric/text transcription */
+WAF,  EQ(WOAF)  /* Official audio file webpage */
+WAR,  EQ(WOAR)  /* Official artist/performer webpage */
+WAS,  EQ(WOAS)  /* Official audio source webpage */
+WCM,  EQ(WCOM)  /* Commercial information */
+WCP,  EQ(WCOP)  /* Copyright/legal information */
+WPB,  EQ(WPUB)  /* Publishers official webpage */
+WXX,  EQ(WXXX)  /* User defined URL link frame */
+%%
+
+static
+int translate_TCON(struct id3_frame *frame, char const *oldid,
+		   id3_byte_t const *data, id3_length_t length)
+{
+  id3_byte_t const *end;
+  enum id3_field_textencoding encoding;
+  id3_ucs4_t *string = 0, *ptr, *endptr;
+  int result = 0;
+
+  /* translate old TCON syntax into multiple strings */
+
+  assert(frame->nfields == 2);
+
+  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
+
+  end = data + length;
+
+  if (id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1)
+    goto fail;
+
+  string = id3_parse_string(&data, end - data, encoding, 0);
+  if (string == 0)
+    goto fail;
+
+  ptr = string;
+  while (*ptr == '(') {
+    if (*++ptr == '(')
+      break;
+
+    endptr = ptr;
+    while (*endptr && *endptr != ')')
+      ++endptr;
+
+    if (*endptr)
+      *endptr++ = 0;
+
+    if (id3_field_addstring(&frame->fields[1], ptr) == -1)
+      goto fail;
+
+    ptr = endptr;
+  }
+
+  if (*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1)
+    goto fail;
+
+  if (0) {
+  fail:
+    result = -1;
+  }
+
+  if (string)
+    free(string);
+
+  return result;
+}
+
+/*
+ * NAME:	compat->fixup()
+ * DESCRIPTION:	finish compatibility translations
+ */
+int id3_compat_fixup(struct id3_tag *tag)
+{
+  struct id3_frame *frame;
+  unsigned int index;
+  id3_ucs4_t timestamp[17] = { 0 };
+  int result = 0;
+
+  /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */
+
+  /*
+   * TYE/TYER: YYYY
+   * TDA/TDAT: DDMM
+   * TIM/TIME: HHMM
+   *
+   * TDRC: yyyy-MM-ddTHH:mm
+   */
+
+  index = 0;
+  while ((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) {
+    char const *id;
+    id3_byte_t const *data, *end;
+    id3_length_t length;
+    enum id3_field_textencoding encoding;
+    id3_ucs4_t *string;
+
+    id = id3_field_getframeid(&frame->fields[0]);
+    assert(id);
+
+    if (strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 &&
+	strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 &&
+	strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0)
+      continue;
+
+    data = id3_field_getbinarydata(&frame->fields[1], &length);
+    assert(data);
+
+    if (length < 1)
+      continue;
+
+    end = data + length;
+
+    encoding = id3_parse_uint(&data, 1);
+    string   = id3_parse_string(&data, end - data, encoding, 0);
+
+    if (string == 0)
+      continue;
+
+    if (id3_ucs4_length(string) < 4) {
+      free(string);
+      continue;
+    }
+
+    if (strcmp(id, "TYER") == 0 ||
+	strcmp(id, "YTYE") == 0) {
+      timestamp[0] = string[0];
+      timestamp[1] = string[1];
+      timestamp[2] = string[2];
+      timestamp[3] = string[3];
+    }
+    else if (strcmp(id, "TDAT") == 0 ||
+	     strcmp(id, "YTDA") == 0) {
+      timestamp[4] = '-';
+      timestamp[5] = string[2];
+      timestamp[6] = string[3];
+      timestamp[7] = '-';
+      timestamp[8] = string[0];
+      timestamp[9] = string[1];
+    }
+    else {  /* TIME or YTIM */
+      timestamp[10] = 'T';
+      timestamp[11] = string[0];
+      timestamp[12] = string[1];
+      timestamp[13] = ':';
+      timestamp[14] = string[2];
+      timestamp[15] = string[3];
+    }
+
+    free(string);
+  }
+
+  if (timestamp[0]) {
+    id3_ucs4_t *strings;
+
+    frame = id3_frame_new("TDRC");
+    if (frame == 0)
+      goto fail;
+
+    strings = timestamp;
+
+    if (id3_field_settextencoding(&frame->fields[0],
+				  ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 ||
+	id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 ||
+	id3_tag_attachframe(tag, frame) == -1) {
+      id3_frame_delete(frame);
+      goto fail;
+    }
+  }
+
+  if (0) {
+  fail:
+    result = -1;
+  }
+
+  return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/compat.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,41 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: compat.h,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_COMPAT_H
+# define LIBID3TAG_COMPAT_H
+
+# include "id3tag.h"
+
+typedef int id3_compat_func_t(struct id3_frame *, char const *,
+			      id3_byte_t const *, id3_length_t);
+
+struct id3_compat {
+  char const *id;
+  char const *equiv;
+  id3_compat_func_t *translate;
+};
+
+struct id3_compat const *id3_compat_lookup(register char const *,
+					   register unsigned int);
+
+int id3_compat_fixup(struct id3_tag *);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/config.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,80 @@
+/* config.h.  Generated by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to enable diagnostic debugging support. */
+/* #undef DEBUG */
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ftruncate' function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to disable debugging assertions. */
+/* #undef NDEBUG */
+
+/* Name of package */
+#define PACKAGE "libid3tag"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "support@underbit.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "ID3 Tag"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "ID3 Tag 0.15.1b"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libid3tag"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.15.1b"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.15.1b"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/crc.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,137 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: crc.c,v 1.11 2004/02/17 02:04:10 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include "id3tag.h"
+# include "crc.h"
+
+static
+unsigned long const crc_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
+  0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
+  0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
+  0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
+  0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
+  0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
+  0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
+
+  0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
+  0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
+  0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
+  0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
+  0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
+  0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
+
+  0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
+  0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
+  0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
+  0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
+  0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
+  0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
+  0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
+
+  0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
+  0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
+  0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
+  0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
+  0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
+  0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
+
+  0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
+  0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
+  0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
+  0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
+  0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
+  0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
+  0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
+  0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
+  0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
+  0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
+  0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
+  0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
+  0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
+
+  0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
+  0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
+  0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
+  0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
+  0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
+  0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
+
+  0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
+  0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
+  0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
+  0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
+  0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
+  0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
+  0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
+};
+
+/*
+ * NAME:	crc->compute()
+ * DESCRIPTION:	calculate CRC-32 value (ISO 3309)
+ */
+unsigned long id3_crc_compute(id3_byte_t const *data, id3_length_t length)
+{
+  register unsigned long crc;
+
+  for (crc = 0xffffffffL; length >= 8; length -= 8) {
+    crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+    crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+    crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+    crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+    crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+    crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+    crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+    crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+  }
+
+  switch (length) {
+  case 7: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+  case 6: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+  case 5: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+  case 4: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+  case 3: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+  case 2: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+  case 1: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+  case 0: break;
+  }
+
+  return crc ^ 0xffffffffL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/crc.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,29 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: crc.h,v 1.8 2004/02/17 02:04:10 rob Exp $
+ */
+
+# ifndef LIBID3TAG_CRC_H
+# define LIBID3TAG_CRC_H
+
+# include "id3tag.h"
+
+unsigned long id3_crc_compute(id3_byte_t const *, id3_length_t);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/debug.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,222 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: debug.c,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# undef malloc
+# undef calloc
+# undef realloc
+# undef free
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+
+# include "debug.h"
+
+# if defined(DEBUG)
+
+# define DEBUG_MAGIC  0xdeadbeefL
+
+struct debug {
+  char const *file;
+  unsigned int line;
+  size_t size;
+  struct debug *next;
+  struct debug *prev;
+  long int magic;
+};
+
+static struct debug *allocated;
+static int registered;
+
+static
+void check(void)
+{
+  struct debug *debug;
+
+  for (debug = allocated; debug; debug = debug->next) {
+    if (debug->magic != DEBUG_MAGIC) {
+      fprintf(stderr, "memory corruption\n");
+      break;
+    }
+
+    fprintf(stderr, "%s:%u: leaked %lu bytes\n",
+	    debug->file, debug->line, debug->size);
+  }
+}
+
+void *id3_debug_malloc(size_t size, char const *file, unsigned int line)
+{
+  struct debug *debug;
+
+  if (!registered) {
+    atexit(check);
+    registered = 1;
+  }
+
+  if (size == 0)
+    fprintf(stderr, "%s:%u: malloc(0)\n", file, line);
+
+  debug = malloc(sizeof(*debug) + size);
+  if (debug == 0) {
+    fprintf(stderr, "%s:%u: malloc(%lu) failed\n", file, line, size);
+    return 0;
+  }
+
+  debug->magic = DEBUG_MAGIC;
+
+  debug->file = file;
+  debug->line = line;
+  debug->size = size;
+
+  debug->next = allocated;
+  debug->prev = 0;
+
+  if (allocated)
+    allocated->prev = debug;
+
+  allocated = debug;
+
+  return ++debug;
+}
+
+void *id3_debug_calloc(size_t nmemb, size_t size,
+		       char const *file, unsigned int line)
+{
+  void *ptr;
+
+  ptr = id3_debug_malloc(nmemb * size, file, line);
+  if (ptr)
+    memset(ptr, 0, nmemb * size);
+
+  return ptr;
+}
+
+void *id3_debug_realloc(void *ptr, size_t size,
+			char const *file, unsigned int line)
+{
+  struct debug *debug, *new;
+
+  if (size == 0) {
+    id3_debug_free(ptr, file, line);
+    return 0;
+  }
+
+  if (ptr == 0)
+    return id3_debug_malloc(size, file, line);
+
+  debug = ptr;
+  --debug;
+
+  if (debug->magic != DEBUG_MAGIC) {
+    fprintf(stderr, "%s:%u: realloc(%p, %lu) memory not allocated\n",
+	    file, line, ptr, size);
+    return 0;
+  }
+
+  new = realloc(debug, sizeof(*debug) + size);
+  if (new == 0) {
+    fprintf(stderr, "%s:%u: realloc(%p, %lu) failed\n", file, line, ptr, size);
+    return 0;
+  }
+
+  if (allocated == debug)
+    allocated = new;
+
+  debug = new;
+
+  debug->file = file;
+  debug->line = line;
+  debug->size = size;
+
+  if (debug->next)
+    debug->next->prev = debug;
+  if (debug->prev)
+    debug->prev->next = debug;
+
+  return ++debug;
+}
+
+void id3_debug_free(void *ptr, char const *file, unsigned int line)
+{
+  struct debug *debug;
+
+  if (ptr == 0) {
+    fprintf(stderr, "%s:%u: free(0)\n", file, line);
+    return;
+  }
+
+  debug = ptr;
+  --debug;
+
+  if (debug->magic != DEBUG_MAGIC) {
+    fprintf(stderr, "%s:%u: free(%p) memory not allocated\n", file, line, ptr);
+    return;
+  }
+
+  debug->magic = 0;
+
+  if (debug->next)
+    debug->next->prev = debug->prev;
+  if (debug->prev)
+    debug->prev->next = debug->next;
+
+  if (allocated == debug)
+    allocated = debug->next;
+
+  free(debug);
+}
+
+void *id3_debug_release(void *ptr, char const *file, unsigned int line)
+{
+  struct debug *debug;
+
+  if (ptr == 0)
+    return 0;
+
+  debug = ptr;
+  --debug;
+
+  if (debug->magic != DEBUG_MAGIC) {
+    fprintf(stderr, "%s:%u: release(%p) memory not allocated\n",
+	    file, line, ptr);
+    return ptr;
+  }
+
+  if (debug->next)
+    debug->next->prev = debug->prev;
+  if (debug->prev)
+    debug->prev->next = debug->next;
+
+  if (allocated == debug)
+    allocated = debug->next;
+
+  memmove(debug, debug + 1, debug->size);
+
+  return debug;
+}
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/debug.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,34 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: debug.h,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_DEBUG_H
+# define LIBID3TAG_DEBUG_H
+
+# include <stdlib.h>
+
+void *id3_debug_malloc(size_t, char const *, unsigned int);
+void *id3_debug_calloc(size_t, size_t, char const *, unsigned int);
+void *id3_debug_realloc(void *, size_t, char const *, unsigned int);
+void id3_debug_free(void *, char const *, unsigned int);
+
+void *id3_debug_release(void *, char const *, unsigned int);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/field.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,895 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: field.c,v 1.16 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+# include <string.h>
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include "id3tag.h"
+# include "field.h"
+# include "frame.h"
+# include "render.h"
+# include "ucs4.h"
+# include "latin1.h"
+# include "parse.h"
+
+/*
+ * NAME:	field->init()
+ * DESCRIPTION:	initialize a field to a default value for the given type
+ */
+void id3_field_init(union id3_field *field, enum id3_field_type type)
+{
+  assert(field);
+
+  switch (field->type = type) {
+  case ID3_FIELD_TYPE_TEXTENCODING:
+  case ID3_FIELD_TYPE_INT8:
+  case ID3_FIELD_TYPE_INT16:
+  case ID3_FIELD_TYPE_INT24:
+  case ID3_FIELD_TYPE_INT32:
+    field->number.value = 0;
+    break;
+
+  case ID3_FIELD_TYPE_LATIN1:
+  case ID3_FIELD_TYPE_LATIN1FULL:
+    field->latin1.ptr = 0;
+    break;
+
+  case ID3_FIELD_TYPE_LATIN1LIST:
+    field->latin1list.nstrings = 0;
+    field->latin1list.strings  = 0;
+
+  case ID3_FIELD_TYPE_STRING:
+  case ID3_FIELD_TYPE_STRINGFULL:
+    field->string.ptr = 0;
+    break;
+
+  case ID3_FIELD_TYPE_STRINGLIST:
+    field->stringlist.nstrings = 0;
+    field->stringlist.strings  = 0;
+    break;
+
+  case ID3_FIELD_TYPE_LANGUAGE:
+    strcpy(field->immediate.value, "XXX");
+    break;
+
+  case ID3_FIELD_TYPE_FRAMEID:
+    strcpy(field->immediate.value, "XXXX");
+    break;
+
+  case ID3_FIELD_TYPE_DATE:
+    memset(field->immediate.value, 0, sizeof(field->immediate.value));
+    break;
+
+  case ID3_FIELD_TYPE_INT32PLUS:
+  case ID3_FIELD_TYPE_BINARYDATA:
+    field->binary.data   = 0;
+    field->binary.length = 0;
+    break;
+  }
+}
+
+/*
+ * NAME:	field->finish()
+ * DESCRIPTION:	reset a field, deallocating memory if necessary
+ */
+void id3_field_finish(union id3_field *field)
+{
+  unsigned int i;
+
+  assert(field);
+
+  switch (field->type) {
+  case ID3_FIELD_TYPE_TEXTENCODING:
+  case ID3_FIELD_TYPE_INT8:
+  case ID3_FIELD_TYPE_INT16:
+  case ID3_FIELD_TYPE_INT24:
+  case ID3_FIELD_TYPE_INT32:
+  case ID3_FIELD_TYPE_LANGUAGE:
+  case ID3_FIELD_TYPE_FRAMEID:
+  case ID3_FIELD_TYPE_DATE:
+    break;
+
+  case ID3_FIELD_TYPE_LATIN1:
+  case ID3_FIELD_TYPE_LATIN1FULL:
+    if (field->latin1.ptr)
+      free(field->latin1.ptr);
+    break;
+
+  case ID3_FIELD_TYPE_LATIN1LIST:
+    for (i = 0; i < field->latin1list.nstrings; ++i)
+      free(field->latin1list.strings[i]);
+
+    if (field->latin1list.strings)
+      free(field->latin1list.strings);
+    break;
+
+  case ID3_FIELD_TYPE_STRING:
+  case ID3_FIELD_TYPE_STRINGFULL:
+    if (field->string.ptr)
+      free(field->string.ptr);
+    break;
+
+  case ID3_FIELD_TYPE_STRINGLIST:
+    for (i = 0; i < field->stringlist.nstrings; ++i)
+      free(field->stringlist.strings[i]);
+
+    if (field->stringlist.strings)
+      free(field->stringlist.strings);
+    break;
+
+  case ID3_FIELD_TYPE_INT32PLUS:
+  case ID3_FIELD_TYPE_BINARYDATA:
+    if (field->binary.data)
+      free(field->binary.data);
+    break;
+  }
+
+  id3_field_init(field, field->type);
+}
+
+/*
+ * NAME:	field->type()
+ * DESCRIPTION:	return the value type of a field
+ */
+enum id3_field_type id3_field_type(union id3_field const *field)
+{
+  assert(field);
+
+  return field->type;
+}
+
+/*
+ * NAME:	field->parse()
+ * DESCRIPTION:	parse a field value
+ */
+int id3_field_parse(union id3_field *field, id3_byte_t const **ptr,
+		    id3_length_t length, enum id3_field_textencoding *encoding)
+{
+  assert(field);
+
+  id3_field_finish(field);
+
+  switch (field->type) {
+  case ID3_FIELD_TYPE_INT32:
+    if (length < 4)
+      goto fail;
+
+    field->number.value = id3_parse_uint(ptr, 4);
+    break;
+
+  case ID3_FIELD_TYPE_INT24:
+    if (length < 3)
+      goto fail;
+
+    field->number.value = id3_parse_uint(ptr, 3);
+    break;
+
+  case ID3_FIELD_TYPE_INT16:
+    if (length < 2)
+      goto fail;
+
+    field->number.value = id3_parse_uint(ptr, 2);
+    break;
+
+  case ID3_FIELD_TYPE_INT8:
+  case ID3_FIELD_TYPE_TEXTENCODING:
+    if (length < 1)
+      goto fail;
+
+    field->number.value = id3_parse_uint(ptr, 1);
+
+    if (field->type == ID3_FIELD_TYPE_TEXTENCODING)
+      *encoding = field->number.value;
+    break;
+
+  case ID3_FIELD_TYPE_LANGUAGE:
+    if (length < 3)
+      goto fail;
+
+    id3_parse_immediate(ptr, 3, field->immediate.value);
+    break;
+
+  case ID3_FIELD_TYPE_FRAMEID:
+    if (length < 4)
+      goto fail;
+
+    id3_parse_immediate(ptr, 4, field->immediate.value);
+    break;
+
+  case ID3_FIELD_TYPE_DATE:
+    if (length < 8)
+      goto fail;
+
+    id3_parse_immediate(ptr, 8, field->immediate.value);
+    break;
+
+  case ID3_FIELD_TYPE_LATIN1:
+  case ID3_FIELD_TYPE_LATIN1FULL:
+    {
+      id3_latin1_t *latin1;
+
+      latin1 = id3_parse_latin1(ptr, length,
+				field->type == ID3_FIELD_TYPE_LATIN1FULL);
+      if (latin1 == 0)
+	goto fail;
+
+      field->latin1.ptr = latin1;
+    }
+    break;
+
+  case ID3_FIELD_TYPE_LATIN1LIST:
+    {
+      id3_byte_t const *end;
+      id3_latin1_t *latin1, **strings;
+
+      end = *ptr + length;
+
+      while (end - *ptr > 0) {
+	latin1 = id3_parse_latin1(ptr, end - *ptr, 0);
+	if (latin1 == 0)
+	  goto fail;
+
+	strings = realloc(field->latin1list.strings,
+			  (field->latin1list.nstrings + 1) * sizeof(*strings));
+	if (strings == 0) {
+	  free(latin1);
+	  goto fail;
+	}
+
+	field->latin1list.strings = strings;
+	field->latin1list.strings[field->latin1list.nstrings++] = latin1;
+      }
+    }
+    break;
+
+  case ID3_FIELD_TYPE_STRING:
+  case ID3_FIELD_TYPE_STRINGFULL:
+    {
+      id3_ucs4_t *ucs4;
+
+      ucs4 = id3_parse_string(ptr, length, *encoding,
+			      field->type == ID3_FIELD_TYPE_STRINGFULL);
+      if (ucs4 == 0)
+	goto fail;
+
+      field->string.ptr = ucs4;
+    }
+    break;
+
+  case ID3_FIELD_TYPE_STRINGLIST:
+    {
+      id3_byte_t const *end;
+      id3_ucs4_t *ucs4, **strings;
+
+      end = *ptr + length;
+
+      while (end - *ptr > 0) {
+	ucs4 = id3_parse_string(ptr, end - *ptr, *encoding, 0);
+	if (ucs4 == 0)
+	  goto fail;
+
+	strings = realloc(field->stringlist.strings,
+			  (field->stringlist.nstrings + 1) * sizeof(*strings));
+	if (strings == 0) {
+	  free(ucs4);
+	  goto fail;
+	}
+
+	field->stringlist.strings = strings;
+	field->stringlist.strings[field->stringlist.nstrings++] = ucs4;
+      }
+    }
+    break;
+
+  case ID3_FIELD_TYPE_INT32PLUS:
+  case ID3_FIELD_TYPE_BINARYDATA:
+    {
+      id3_byte_t *data;
+
+      data = id3_parse_binary(ptr, length);
+      if (data == 0)
+	goto fail;
+
+      field->binary.data   = data;
+      field->binary.length = length;
+    }
+    break;
+  }
+
+  return 0;
+
+ fail:
+  return -1;
+}
+
+/*
+ * NAME:	field->render()
+ * DESCRIPTION:	render a field value
+ */
+id3_length_t id3_field_render(union id3_field const *field, id3_byte_t **ptr,
+			      enum id3_field_textencoding *encoding,
+			      int terminate)
+{
+  id3_length_t size;
+  unsigned int i;
+
+  assert(field && encoding);
+
+  switch (field->type) {
+  case ID3_FIELD_TYPE_INT32:
+    return id3_render_int(ptr, field->number.value, 4);
+
+  case ID3_FIELD_TYPE_INT24:
+    return id3_render_int(ptr, field->number.value, 3);
+
+  case ID3_FIELD_TYPE_INT16:
+    return id3_render_int(ptr, field->number.value, 2);
+
+  case ID3_FIELD_TYPE_TEXTENCODING:
+    *encoding = field->number.value;
+  case ID3_FIELD_TYPE_INT8:
+    return id3_render_int(ptr, field->number.value, 1);
+
+  case ID3_FIELD_TYPE_LATIN1:
+  case ID3_FIELD_TYPE_LATIN1FULL:
+    return id3_render_latin1(ptr, field->latin1.ptr, terminate);
+
+  case ID3_FIELD_TYPE_LATIN1LIST:
+    size = 0;
+    for (i = 0; i < field->latin1list.nstrings; ++i) {
+      size += id3_render_latin1(ptr, field->latin1list.strings[i],
+				(i < field->latin1list.nstrings - 1) ||
+				terminate);
+    }
+    return size;
+
+  case ID3_FIELD_TYPE_STRING:
+  case ID3_FIELD_TYPE_STRINGFULL: // here !! --yaz
+    return id3_render_string(ptr, field->string.ptr, *encoding, terminate);
+
+  case ID3_FIELD_TYPE_STRINGLIST:
+    size = 0;
+    for (i = 0; i < field->stringlist.nstrings; ++i) {
+      size += id3_render_string(ptr, field->stringlist.strings[i], *encoding,
+				(i < field->stringlist.nstrings - 1) ||
+				terminate);
+    }
+    return size;
+
+  case ID3_FIELD_TYPE_LANGUAGE:
+    return id3_render_immediate(ptr, field->immediate.value, 3);
+
+  case ID3_FIELD_TYPE_FRAMEID:
+    return id3_render_immediate(ptr, field->immediate.value, 4);
+
+  case ID3_FIELD_TYPE_DATE:
+    return id3_render_immediate(ptr, field->immediate.value, 8);
+
+  case ID3_FIELD_TYPE_INT32PLUS:
+  case ID3_FIELD_TYPE_BINARYDATA:
+    return id3_render_binary(ptr, field->binary.data, field->binary.length);
+  }
+
+  return 0;
+}
+
+/*
+ * NAME:	field->setint()
+ * DESCRIPTION:	set the value of an int field
+ */
+int id3_field_setint(union id3_field *field, signed long number)
+{
+  assert(field);
+
+  switch (field->type) {
+  case ID3_FIELD_TYPE_INT8:
+    if (number > 0x7f || number < -0x80)
+      return -1;
+    break;
+
+  case ID3_FIELD_TYPE_INT16:
+    if (number > 0x7fff || number < -0x8000)
+      return -1;
+    break;
+
+  case ID3_FIELD_TYPE_INT24:
+    if (number > 0x7fffffL || number < -0x800000L)
+      return -1;
+    break;
+
+  case ID3_FIELD_TYPE_INT32:
+    if (number > 0x7fffffffL || number < -0x80000000L)
+      return -1;
+    break;
+
+  default:
+    return -1;
+  }
+
+  id3_field_finish(field);
+
+  field->number.value = number;
+
+  return 0;
+}
+
+/*
+ * NAME:	field->settextencoding()
+ * DESCRIPTION:	set the value of a textencoding field
+ */
+int id3_field_settextencoding(union id3_field *field,
+			      enum id3_field_textencoding encoding)
+{
+  assert(field);
+
+  printf("field type=%d ", field->type);
+  if (field->type != ID3_FIELD_TYPE_TEXTENCODING) {
+	  printf("not textencoding\n");
+    return -1;
+  }
+
+  id3_field_finish(field);
+
+  field->number.value = encoding;
+
+  return 0;
+}
+
+static
+int set_latin1(union id3_field *field, id3_latin1_t const *latin1)
+{
+  id3_latin1_t *data;
+
+  if (latin1 == 0 || *latin1 == 0)
+    data = 0;
+  else {
+    data = id3_latin1_duplicate(latin1);
+    if (data == 0)
+      return -1;
+  }
+
+  field->latin1.ptr = data;
+
+  return 0;
+}
+
+/*
+ * NAME:	field->setlatin1()
+ * DESCRIPTION:	set the value of a latin1 field
+ */
+int id3_field_setlatin1(union id3_field *field, id3_latin1_t const *latin1)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_LATIN1)
+    return -1;
+
+  id3_field_finish(field);
+
+  if (latin1) {
+    id3_latin1_t const *ptr;
+
+    for (ptr = latin1; *ptr; ++ptr) {
+      if (*ptr == '\n')
+	return -1;
+    }
+  }
+
+  return set_latin1(field, latin1);
+}
+
+/*
+ * NAME:	field->setfulllatin1()
+ * DESCRIPTION:	set the value of a full latin1 field
+ */
+int id3_field_setfulllatin1(union id3_field *field, id3_latin1_t const *latin1)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_LATIN1FULL)
+    return -1;
+
+  id3_field_finish(field);
+
+  return set_latin1(field, latin1);
+}
+
+static
+int set_string(union id3_field *field, id3_ucs4_t const *string)
+{
+  id3_ucs4_t *data;
+
+  if (string == 0 || *string == 0)
+    data = 0;
+  else {
+    data = id3_ucs4_duplicate(string);
+    if (data == 0)
+      return -1;
+  }
+
+  field->string.ptr = data;
+
+  return 0;
+}
+
+/*
+ * NAME:	field->setstring()
+ * DESCRIPTION:	set the value of a string field
+ */
+int id3_field_setstring(union id3_field *field, id3_ucs4_t const *string)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_STRING)
+    return -1;
+
+  id3_field_finish(field);
+
+  if (string) {
+    id3_ucs4_t const *ptr;
+
+    for (ptr = string; *ptr; ++ptr) {
+      if (*ptr == '\n')
+	return -1;
+    }
+  }
+
+  return set_string(field, string);
+}
+
+/*
+ * NAME:	field->setfullstring()
+ * DESCRIPTION:	set the value of a full string field
+ */
+int id3_field_setfullstring(union id3_field *field, id3_ucs4_t const *string)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_STRINGFULL)
+    return -1;
+
+  id3_field_finish(field);
+
+  return set_string(field, string);
+}
+
+/*
+ * NAME:	field->setstrings()
+ * DESCRIPTION:	set the value of a stringlist field
+ */
+int id3_field_setstrings(union id3_field *field,
+			 unsigned int length, id3_ucs4_t **ptrs)
+{
+  id3_ucs4_t **strings;
+  unsigned int i;
+
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_STRINGLIST)
+    return -1;
+
+  id3_field_finish(field);
+
+  if (length == 0)
+    return 0;
+
+  strings = malloc(length * sizeof(*strings));
+  if (strings == 0)
+    return -1;
+
+  for (i = 0; i < length; ++i) {
+    strings[i] = id3_ucs4_duplicate(ptrs[i]);
+    if (strings[i] == 0) {
+      while (i--)
+	free(strings[i]);
+
+      free(strings);
+      return -1;
+    }
+  }
+
+  field->stringlist.strings  = strings;
+  field->stringlist.nstrings = length;
+
+  return 0;
+}
+
+/*
+ * NAME:	field->addstring()
+ * DESCRIPTION:	add a string to a stringlist field
+ */
+int id3_field_addstring(union id3_field *field, id3_ucs4_t const *string)
+{
+  id3_ucs4_t *new, **strings;
+
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_STRINGLIST)
+    return -1;
+
+  if (string == 0)
+    string = id3_ucs4_empty;
+
+  new = id3_ucs4_duplicate(string);
+  if (new == 0)
+    return -1;
+
+  strings = realloc(field->stringlist.strings,
+		    (field->stringlist.nstrings + 1) * sizeof(*strings));
+  if (strings == 0) {
+    free(new);
+    return -1;
+  }
+
+  field->stringlist.strings = strings;
+  field->stringlist.strings[field->stringlist.nstrings++] = new;
+
+  return 0;
+}
+
+/*
+ * NAME:	field->setlanguage()
+ * DESCRIPTION:	set the value of a language field
+ */
+int id3_field_setlanguage(union id3_field *field, char const *language)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_LANGUAGE)
+    return -1;
+
+  id3_field_finish(field);
+
+  if (language) {
+    if (strlen(language) != 3)
+      return -1;
+
+    strcpy(field->immediate.value, language);
+  }
+
+  return 0;
+}
+
+/*
+ * NAME:	field->setframeid()
+ * DESCRIPTION:	set the value of a frameid field
+ */
+int id3_field_setframeid(union id3_field *field, char const *id)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_FRAMEID ||
+      !id3_frame_validid(id))
+    return -1;
+
+  id3_field_finish(field);
+
+  field->immediate.value[0] = id[0];
+  field->immediate.value[1] = id[1];
+  field->immediate.value[2] = id[2];
+  field->immediate.value[3] = id[3];
+  field->immediate.value[4] = 0;
+
+  return 0;
+}
+
+/*
+ * NAME:	field->setbinarydata()
+ * DESCRIPTION:	set the value of a binarydata field
+ */
+int id3_field_setbinarydata(union id3_field *field,
+			    id3_byte_t const *data, id3_length_t length)
+{
+  id3_byte_t *mem;
+
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_BINARYDATA)
+    return -1;
+
+  id3_field_finish(field);
+
+  if (length == 0)
+    mem = 0;
+  else {
+    mem = malloc(length);
+    if (mem == 0)
+      return -1;
+
+    assert(data);
+
+    memcpy(mem, data, length);
+  }
+
+  field->binary.data   = mem;
+  field->binary.length = length;
+
+  return 0;
+}
+
+/*
+ * NAME:	field->getint()
+ * DESCRIPTION:	return the value of an integer field
+ */
+signed long id3_field_getint(union id3_field const *field)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_INT8 &&
+      field->type != ID3_FIELD_TYPE_INT16 &&
+      field->type != ID3_FIELD_TYPE_INT24 &&
+      field->type != ID3_FIELD_TYPE_INT32)
+    return -1;
+
+  return field->number.value;
+}
+
+/*
+ * NAME:	field->gettextencoding()
+ * DESCRIPTION:	return the value of a text encoding field
+ */
+enum id3_field_textencoding
+id3_field_gettextencoding(union id3_field const *field)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_TEXTENCODING)
+    return -1;
+
+  return field->number.value;
+}
+
+/*
+ * NAME:	field->getlatin1()
+ * DESCRIPTION:	return the value of a latin1 field
+ */
+id3_latin1_t const *id3_field_getlatin1(union id3_field const *field)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_LATIN1)
+    return 0;
+
+  return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) "";
+}
+
+/*
+ * NAME:	field->getfulllatin1()
+ * DESCRIPTION:	return the value of a full latin1 field
+ */
+id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *field)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_LATIN1FULL)
+    return 0;
+
+  return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) "";
+}
+
+/*
+ * NAME:	field->getstring()
+ * DESCRIPTION:	return the value of a string field
+ */
+id3_ucs4_t const *id3_field_getstring(union id3_field const *field)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_STRING)
+    return 0;
+
+  return field->string.ptr ? field->string.ptr : id3_ucs4_empty;
+}
+
+/*
+ * NAME:	field->getfullstring()
+ * DESCRIPTION:	return the value of a fullstring field
+ */
+id3_ucs4_t const *id3_field_getfullstring(union id3_field const *field)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_STRINGFULL) {
+	  printf("not stringfull\n");
+	  return 0;
+  }
+
+  return field->string.ptr ? field->string.ptr : id3_ucs4_empty;
+}
+
+/*
+ * NAME:	field->getnstrings()
+ * DESCRIPTION:	return the number of strings in a stringlist field
+ */
+unsigned int id3_field_getnstrings(union id3_field const *field)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_STRINGLIST)
+    return 0;
+
+  return field->stringlist.nstrings;
+}
+
+/*
+ * NAME:	field->getstrings()
+ * DESCRIPTION:	return one value of a stringlist field
+ */
+id3_ucs4_t const *id3_field_getstrings(union id3_field const *field,
+				       unsigned int index)
+{
+  id3_ucs4_t const *string;
+
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_STRINGLIST ||
+      index >= field->stringlist.nstrings)
+    return 0;
+
+  string = field->stringlist.strings[index];
+
+  return string ? string : id3_ucs4_empty;
+}
+
+/*
+ * NAME:	field->getframeid()
+ * DESCRIPTION:	return the value of a frameid field
+ */
+char const *id3_field_getframeid(union id3_field const *field)
+{
+  assert(field);
+
+  if (field->type != ID3_FIELD_TYPE_FRAMEID)
+    return 0;
+
+  return field->immediate.value;
+}
+
+/*
+ * NAME:	field->getbinarydata()
+ * DESCRIPTION:	return the value of a binarydata field
+ */
+id3_byte_t const *id3_field_getbinarydata(union id3_field const *field,
+					  id3_length_t *length)
+{
+  static id3_byte_t const empty;
+
+  assert(field && length);
+
+  if (field->type != ID3_FIELD_TYPE_BINARYDATA)
+    return 0;
+
+  assert(field->binary.length == 0 || field->binary.data);
+
+  *length = field->binary.length;
+
+  return field->binary.data ? field->binary.data : &empty;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/field.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,36 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: field.h,v 1.9 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_FIELD_H
+# define LIBID3TAG_FIELD_H
+
+# include "id3tag.h"
+
+void id3_field_init(union id3_field *, enum id3_field_type);
+void id3_field_finish(union id3_field *);
+
+int id3_field_parse(union id3_field *, id3_byte_t const **,
+		    id3_length_t, enum id3_field_textencoding *);
+
+id3_length_t id3_field_render(union id3_field const *, id3_byte_t **,
+			      enum id3_field_textencoding *, int);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/file.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,777 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: file.c,v 1.21 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include "id3tag.h"
+# include "file.h"
+# include "tag.h"
+# include "field.h"
+
+#define AUDACIOUS 1
+//#undef AUDACIOUS
+
+#ifdef AUDACIOUS
+  #undef G_BEGIN_DECLS
+  #undef G_END_DECLS
+  #include <audacious/vfs.h>
+#else
+  #define VFSFile FILE
+  #define vfs_fopen fopen
+  #define vfs_fclose fclose
+  #define vfs_fseek fseek
+  #define vfs_ftell ftell
+  #define vfs_rewind rewind
+  #define vfs_fread fread
+  #define vfs_fwrite fwrite
+  #define vfs_truncate(x, y) ftruncate((fileno(x)), (y))
+#endif
+
+struct filetag {
+  struct id3_tag *tag;
+  unsigned long location;
+  id3_length_t length;
+};
+
+struct id3_file {
+  VFSFile *iofile;
+  enum id3_file_mode mode;
+  char *path;
+
+  int flags;
+
+  struct id3_tag *primary;
+
+  unsigned int ntags;
+  struct filetag *tags;
+};
+
+enum {
+  ID3_FILE_FLAG_ID3V1 = 0x0001
+};
+
+/*
+ * NAME:	query_tag()
+ * DESCRIPTION:	check for a tag at a file's current position
+ */
+static
+signed long query_tag(VFSFile *iofile)
+{
+  int save_position;
+  id3_byte_t query[ID3_TAG_QUERYSIZE];
+  signed long size;
+
+  save_position = vfs_ftell(iofile);
+  if (save_position == -1)
+    return 0;
+
+  size = id3_tag_query(query, vfs_fread(query, 1, sizeof(query), iofile));
+
+  if(vfs_fseek(iofile, save_position, SEEK_SET) == -1)
+    return 0;
+
+  return size;
+}
+
+/*
+ * NAME:	read_tag()
+ * DESCRIPTION:	read and parse a tag at a file's current position
+ */
+static
+struct id3_tag *read_tag(VFSFile *iofile, id3_length_t size)
+{
+  id3_byte_t *data;
+  struct id3_tag *tag = 0;
+
+  data = malloc(size);
+  if (data) {
+    if (vfs_fread(data, size, 1, iofile) == 1)
+      tag = id3_tag_parse(data, size);
+
+    free(data);
+  }
+
+  return tag;
+}
+
+/*
+ * NAME:	update_primary()
+ * DESCRIPTION:	update the primary tag with data from a new tag
+ */
+static
+int update_primary(struct id3_tag *tag, struct id3_tag const *new)
+{
+  unsigned int i;
+  struct id3_frame *frame;
+
+  if (new) {
+    if (!(new->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE))
+      id3_tag_clearframes(tag);
+
+    i = 0;
+    while ((frame = id3_tag_findframe(new, 0, i++))) {
+      if (id3_tag_attachframe(tag, frame) == -1)
+	return -1;
+    }
+  }
+
+  return 0;
+}
+
+/*
+ * NAME:	tag_compare()
+ * DESCRIPTION:	tag sort function for qsort()
+ */
+static
+int tag_compare(const void *a, const void *b)
+{
+  struct filetag const *tag1 = a, *tag2 = b;
+
+  if (tag1->location < tag2->location)
+    return -1;
+  else if (tag1->location > tag2->location)
+    return +1;
+
+  return 0;
+}
+
+/*
+ * NAME:	add_filetag()
+ * DESCRIPTION:	add a new file tag entry
+ */
+static
+int add_filetag(struct id3_file *file, struct filetag const *filetag)
+{
+  struct filetag *tags;
+
+  tags = realloc(file->tags, (file->ntags + 1) * sizeof(*tags));
+  if (tags == 0)
+    return -1;
+
+  file->tags = tags;
+  file->tags[file->ntags++] = *filetag;
+
+  /* sort tags by location */
+
+  if (file->ntags > 1)
+    qsort(file->tags, file->ntags, sizeof(file->tags[0]), tag_compare);
+
+  return 0;
+}
+
+/*
+ * NAME:	del_filetag()
+ * DESCRIPTION:	delete a file tag entry
+ */
+static
+void del_filetag(struct id3_file *file, unsigned int index)
+{
+  assert(index < file->ntags);
+
+  while (index < file->ntags - 1) {
+    file->tags[index] = file->tags[index + 1];
+    ++index;
+  }
+
+  --file->ntags;
+}
+
+/*
+ * NAME:	add_tag()
+ * DESCRIPTION:	read, parse, and add a tag to a file structure
+ */
+static
+struct id3_tag *add_tag(struct id3_file *file, id3_length_t length)
+{
+  long location;
+  unsigned int i;
+  struct filetag filetag;
+  struct id3_tag *tag;
+
+  location = vfs_ftell(file->iofile);
+  if (location == -1)
+    return 0;
+
+  /* check for duplication/overlap */
+  {
+    unsigned long begin1, end1, begin2, end2;
+
+    begin1 = location;
+    end1   = begin1 + length;
+
+    for (i = 0; i < file->ntags; ++i) {
+      begin2 = file->tags[i].location;
+      end2   = begin2 + file->tags[i].length;
+
+      if (begin1 == begin2 && end1 == end2)
+	return file->tags[i].tag;  /* duplicate */
+
+      if (begin1 < end2 && end1 > begin2)
+	return 0;  /* overlap */
+    }
+  }
+
+  tag = read_tag(file->iofile, length);
+
+  filetag.tag      = tag;
+  filetag.location = location;
+  filetag.length   = length;
+
+  if (add_filetag(file, &filetag) == -1 ||
+      update_primary(file->primary, tag) == -1) {
+    if (tag)
+      id3_tag_delete(tag);
+    return 0;
+  }
+
+  if (tag)
+    id3_tag_addref(tag);
+
+  return tag;
+}
+
+/*
+ * NAME:	search_tags()
+ * DESCRIPTION:	search for tags in a file
+ */
+//static
+int search_tags(struct id3_file *file)
+{
+  int save_position;
+  signed long size;
+
+  /*
+   * save the current seek position
+   *
+   * We also verify the stream is seekable by calling fsetpos(), since
+   * fgetpos() alone is not reliable enough for this purpose.
+   *
+   * [Apparently not even fsetpos() is sufficient under Win32.]
+   */
+
+//  if (fgetpos(file->iofile, &save_position) == -1 ||
+//      fsetpos(file->iofile, &save_position) == -1)
+//  if (save_position = vfs_ftell(file->iofile) == -1 ||
+//      vfs_fseek(file->iofile, save_position, SEEK_SET) == -1)
+  if((save_position = vfs_ftell(file->iofile)) == -1)
+    return -1;
+
+  /* look for an ID3v1 tag */
+
+  if (vfs_fseek(file->iofile, -128, SEEK_END) == 0) {
+    size = query_tag(file->iofile);
+    if (size > 0) {
+      struct id3_tag const *tag;
+
+      tag = add_tag(file, size);
+
+      /* if this is indeed an ID3v1 tag, mark the file so */
+
+      if (tag && (ID3_TAG_VERSION_MAJOR(id3_tag_version(tag)) == 1))
+	file->flags |= ID3_FILE_FLAG_ID3V1;
+    }
+  }
+
+  /* look for a tag at the beginning of the file */
+
+  vfs_rewind(file->iofile);
+
+  size = query_tag(file->iofile);
+  if (size > 0) {
+    struct id3_tag const *tag;
+    struct id3_frame const *frame;
+
+    tag = add_tag(file, size);
+
+    /* locate tags indicated by SEEK frames */
+
+    while (tag && (frame = id3_tag_findframe(tag, "SEEK", 0))) {
+      long seek;
+
+      seek = id3_field_getint(id3_frame_field(frame, 0));
+      if (seek < 0 || vfs_fseek(file->iofile, seek, SEEK_CUR) == -1)
+	break;
+
+      size = query_tag(file->iofile);
+      tag  = (size > 0) ? add_tag(file, size) : 0;
+    }
+  }
+
+  /* look for a tag at the end of the file (before any ID3v1 tag) */
+
+  if (vfs_fseek(file->iofile, ((file->flags & ID3_FILE_FLAG_ID3V1) ? -128 : 0) +
+	    -10, SEEK_END) == 0) {
+    size = query_tag(file->iofile);
+    if (size < 0 && vfs_fseek(file->iofile, size, SEEK_CUR) == 0) {
+      size = query_tag(file->iofile);
+      if (size > 0)
+	add_tag(file, size);
+    }
+  }
+
+#ifndef AUDACIOUS
+  clearerr(file->iofile);
+#endif
+
+  /* restore seek position */
+
+//  if (fsetpos(file->iofile, &save_position) == -1)
+  if (vfs_fseek(file->iofile, save_position, SEEK_SET) == -1)
+    return -1;
+
+  /* set primary tag options and target padded length for convenience */
+
+  if ((file->ntags > 0 && !(file->flags & ID3_FILE_FLAG_ID3V1)) ||
+      (file->ntags > 1 &&  (file->flags & ID3_FILE_FLAG_ID3V1))) {
+    if (file->tags[0].location == 0)
+      id3_tag_setlength(file->primary, file->tags[0].length);
+    else
+      id3_tag_options(file->primary, ID3_TAG_OPTION_APPENDEDTAG, ~0);
+  }
+
+  return 0;
+}
+
+/*
+ * NAME:	finish_file()
+ * DESCRIPTION:	release memory associated with a file
+ */
+static
+void finish_file(struct id3_file *file)
+{
+  unsigned int i;
+
+  if (file->path)
+    free(file->path);
+
+  if (file->primary) {
+    id3_tag_delref(file->primary);
+    id3_tag_delete(file->primary);
+  }
+
+  for (i = 0; i < file->ntags; ++i) {
+    struct id3_tag *tag;
+
+    tag = file->tags[i].tag;
+    if (tag) {
+      id3_tag_delref(tag);
+      id3_tag_delete(tag);
+    }
+  }
+
+  if (file->tags)
+    free(file->tags);
+
+  free(file);
+}
+
+/*
+ * NAME:	new_file()
+ * DESCRIPTION:	create a new file structure and load tags
+ */
+static
+struct id3_file *new_file(VFSFile *iofile, enum id3_file_mode mode,
+			  char const *path)
+{
+  struct id3_file *file;
+
+  file = malloc(sizeof(*file));
+  if (file == 0)
+    goto fail;
+
+  file->iofile  = iofile;
+  file->mode    = mode;
+  file->path    = path ? strdup(path) : 0;
+
+  file->flags   = 0;
+
+  file->ntags   = 0;
+  file->tags    = 0;
+
+  file->primary = id3_tag_new();
+  if (file->primary == 0)
+    goto fail;
+
+  id3_tag_addref(file->primary);
+
+  /* load tags from the file */
+
+  if (search_tags(file) == -1)
+    goto fail;
+
+  id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1,
+		  (file->flags & ID3_FILE_FLAG_ID3V1) ? ~0 : 0);
+
+  if (0) {
+  fail:
+    if (file) {
+      finish_file(file);
+      file = 0;
+    }
+  }
+
+  return file;
+}
+
+
+/*
+ * NAME:	file->open()
+ * DESCRIPTION:	open a file given its pathname
+ */
+struct id3_file *id3_file_open(char const *path, enum id3_file_mode mode)
+{
+  VFSFile *iofile;
+  struct id3_file *file;
+
+  assert(path);
+
+  iofile = vfs_fopen(path, (mode == ID3_FILE_MODE_READWRITE) ? "r+b" : "rb");
+  if (iofile == 0){
+    printf("id3_file_open: iofile failed\n");
+    return 0;
+  }
+  file = new_file(iofile, mode, path);
+  if (file == 0){
+    printf("id3_file_open: file failed\n");
+    vfs_fclose(iofile);
+  }
+
+  return file;
+}
+
+/*
+ * NAME:	file->fdopen()
+ * DESCRIPTION:	open a file using an existing file descriptor
+ */
+#ifndef AUDACIOUS
+struct id3_file *id3_file_fdopen(int fd, enum id3_file_mode mode)
+{
+# if 1 || defined(HAVE_UNISTD_H)
+  VFSFile *iofile;
+  struct id3_file *file;
+
+  iofile = fdopen(fd, (mode == ID3_FILE_MODE_READWRITE) ? "r+b" : "rb");
+  if (iofile == 0)
+    return 0;
+
+  file = new_file(iofile, mode, 0);
+  if (file == 0) {
+    int save_fd;
+
+    /* close iofile without closing fd */
+
+    save_fd = dup(fd);
+
+    fclose(iofile);
+
+    dup2(save_fd, fd);
+    close(save_fd);
+  }
+
+  return file;
+# else
+  return 0;
+# endif
+}
+#endif
+
+/*
+ * NAME:	file->close()
+ * DESCRIPTION:	close a file and delete its associated tags
+ */
+int id3_file_close(struct id3_file *file)
+{
+  int result = 0;
+
+  assert(file);
+
+  if (vfs_fclose(file->iofile) == EOF)
+    result = -1;
+
+  finish_file(file);
+
+  return result;
+}
+
+/*
+ * NAME:	file->tag()
+ * DESCRIPTION:	return the primary tag structure for a file
+ */
+struct id3_tag *id3_file_tag(struct id3_file const *file)
+{
+  assert(file);
+
+  return file->primary;
+}
+
+/*
+ * NAME:	v1_write()
+ * DESCRIPTION:	write ID3v1 tag modifications to a file
+ */
+static
+int v1_write(struct id3_file *file,
+	     id3_byte_t const *data, id3_length_t length)
+{
+  assert(!data || length == 128);
+
+  if (data) {
+    long location;
+
+    if (vfs_fseek(file->iofile, (file->flags & ID3_FILE_FLAG_ID3V1) ? -128 : 0,
+	      SEEK_END) == -1 ||
+	(location = vfs_ftell(file->iofile)) == -1 ||
+#ifdef AUDACIOUS
+	vfs_fwrite(data, 128, 1, file->iofile) != 1 )
+#else
+	vfs_fwrite(data, 128, 1, file->iofile) != 1 ||
+	fflush(file->iofile) == EOF) //XXX
+#endif
+      return -1;
+
+    /* add file tag reference */
+
+    if (!(file->flags & ID3_FILE_FLAG_ID3V1)) {
+      struct filetag filetag;
+
+      filetag.tag      = 0;
+      filetag.location = location;
+      filetag.length   = 128;
+
+      if (add_filetag(file, &filetag) == -1)
+	return -1;
+
+      file->flags |= ID3_FILE_FLAG_ID3V1;
+    }
+  }
+# if defined(HAVE_FTRUNCATE)
+  else if (file->flags & ID3_FILE_FLAG_ID3V1) {
+    long length;
+
+    if (vfs_fseek(file->iofile, 0, SEEK_END) == -1)
+      return -1;
+
+    length = vfs_ftell(file->iofile);
+    if (length == -1 ||
+	(length >= 0 && length < 128))
+      return -1;
+
+//    if (ftruncate(fileno(file->iofile), length - 128) == -1) //XXX
+    if (vfs_truncate(file->iofile, length - 128) == -1)
+      return -1;
+
+    /* delete file tag reference */
+
+    del_filetag(file, file->ntags - 1);
+
+    file->flags &= ~ID3_FILE_FLAG_ID3V1;
+  }
+# endif
+
+  return 0;
+}
+
+/*
+ * NAME:	v2_write()
+ * DESCRIPTION:	write ID3v2 tag modifications to a file
+ */
+static
+int v2_write(struct id3_file *file,
+	     id3_byte_t const *data, id3_length_t length)
+{
+  assert(!data || length > 0);
+
+  // append a new id3v2 tag to the file which doesn't have any tag or only have v1tag.
+  if(data &&
+     ((file->ntags == 0) || // no tag
+      (file->ntags == 1 && (file->flags & ID3_FILE_FLAG_ID3V1))) ) { // only v1 tag exists
+
+      struct filetag filetag;
+
+      printf("append v2tag\n");
+
+      filetag.tag = 0;
+      filetag.location = 0; // begining of the file.
+      filetag.length = 0;
+      
+      if(add_filetag(file, &filetag) == -1)
+          return -1;
+
+      if(file->ntags == 1)
+          file->flags = 0;
+      if(file->ntags == 2)
+          file->flags |= ID3_FILE_FLAG_ID3V1;
+  }
+
+  if (!data
+      ||  (!(file->ntags == 1 && !(file->flags & ID3_FILE_FLAG_ID3V1)) && 
+           !(file->ntags == 2 &&  (file->flags & ID3_FILE_FLAG_ID3V1)))) {
+    /* no v2 tag. nothing to do */
+    goto done;
+  }
+
+  if (file->tags[0].length == length) {
+    /* easy special case: rewrite existing tag in-place */
+
+    if (vfs_fseek(file->iofile, file->tags[0].location, SEEK_SET) == -1 ||
+#ifdef AUDACIOUS
+	vfs_fwrite(data, length, 1, file->iofile) != 1)
+#else
+	vfs_fwrite(data, length, 1, file->iofile) != 1 ||
+	fflush(file->iofile) == EOF)
+#endif
+      return -1;
+
+    goto done;
+  } else {
+    /* the new tag has a different size */
+    int file_size;
+    int remainder_size;
+    char *remainder;
+
+    /* read in the remainder of the file */
+    vfs_fseek(file->iofile, 0, SEEK_END);
+    file_size = vfs_ftell(file->iofile);
+    remainder_size = file_size - file->tags[0].location - file->tags[0].length;
+    remainder = (char*)malloc(remainder_size);
+    if (vfs_fseek(file->iofile, file->tags[0].location + file->tags[0].length, SEEK_SET) == -1 ||
+	vfs_fread(remainder, remainder_size, 1, file->iofile) != 1) {
+      free(remainder);
+      return -1;
+    }
+
+    /* write the tag where the old one was */
+    if (vfs_fseek(file->iofile, file->tags[0].location, SEEK_SET) == -1 ||
+	vfs_fwrite(data, length, 1, file->iofile) != 1) {
+      free(remainder);
+      return -1;
+    }
+
+    /* write the reaminder */
+    if (vfs_fwrite(remainder, remainder_size, 1, file->iofile) != 1) {
+      free(remainder);
+      return -1;
+  }
+
+    free(remainder);
+
+    /* flush the FILE */
+#ifndef AUDACIOUS
+    if (fflush(file->iofile) == EOF)
+      return -1;
+#endif
+    /* truncate if required */
+    if (vfs_ftell(file->iofile) < file_size)
+      vfs_truncate(file->iofile, vfs_ftell(file->iofile));
+  }
+
+ done:
+  return 0;
+}
+
+/*
+ * NAME:	file->update()
+ * DESCRIPTION:	rewrite tag(s) to a file
+ */
+int id3_file_update(struct id3_file *file)
+{
+  int options, result = 0;
+  id3_length_t v1size = 0, v2size = 0;
+  id3_byte_t id3v1_data[128], *id3v1 = 0, *id3v2 = 0;
+
+  assert(file);
+
+  if (file->mode != ID3_FILE_MODE_READWRITE)
+    return -1;
+
+  options = id3_tag_options(file->primary, 0, 0);
+
+  /* render ID3v1 */
+
+  if (options & ID3_TAG_OPTION_ID3V1) {
+    v1size = id3_tag_render(file->primary, 0);
+    if (v1size) {
+      assert(v1size == sizeof(id3v1_data));
+
+      v1size = id3_tag_render(file->primary, id3v1_data);
+      if (v1size) {
+	assert(v1size == sizeof(id3v1_data));
+	id3v1 = id3v1_data;
+      }
+    }
+  }
+
+  /* render ID3v2 */
+
+  id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1, 0);
+
+  v2size = id3_tag_render(file->primary, 0);
+  if (v2size) {
+    id3v2 = malloc(v2size);
+    if (id3v2 == 0)
+      goto fail;
+
+    v2size = id3_tag_render(file->primary, id3v2);
+    if (v2size == 0) {
+      free(id3v2);
+      id3v2 = 0;
+    }
+  }
+
+  /* write tags */
+
+  if (v2_write(file, id3v2, v2size) == -1 ||
+      v1_write(file, id3v1, v1size) == -1)
+    goto fail;
+
+  vfs_rewind(file->iofile);
+
+  /* update file tags array? ... */
+
+  if (0) {
+  fail:
+    result = -1;
+  }
+
+  /* clean up; restore tag options */
+
+  if (id3v2)
+    free(id3v2);
+
+  id3_tag_options(file->primary, ~0, options);
+
+  return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/file.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,25 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: file.h,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_FILE_H
+# define LIBID3TAG_FILE_H
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/frame.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,627 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: frame.c,v 1.15 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+# include <string.h>
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include "id3tag.h"
+# include "frame.h"
+# include "frametype.h"
+# include "compat.h"
+# include "field.h"
+# include "render.h"
+# include "parse.h"
+# include "util.h"
+
+static
+int valid_idchar(char c)
+{
+  return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
+}
+
+/*
+ * NAME:	frame->validid()
+ * DESCRIPTION:	return true if the parameter string is a legal frame ID
+ */
+int id3_frame_validid(char const *id)
+{
+  return id &&
+    valid_idchar(id[0]) &&
+    valid_idchar(id[1]) &&
+    valid_idchar(id[2]) &&
+    valid_idchar(id[3]);
+}
+
+/*
+ * NAME:	frame->new()
+ * DESCRIPTION:	allocate and return a new frame
+ */
+struct id3_frame *id3_frame_new(char const *id)
+{
+  struct id3_frametype const *frametype;
+  struct id3_frame *frame;
+  unsigned int i;
+
+  if (!id3_frame_validid(id))
+    return 0;
+
+  frametype = id3_frametype_lookup(id, 4);
+  if (frametype == 0) {
+    switch (id[0]) {
+    case 'T':
+      frametype = &id3_frametype_text;
+      break;
+
+    case 'W':
+      frametype = &id3_frametype_url;
+      break;
+
+    case 'X':
+    case 'Y':
+    case 'Z':
+      frametype = &id3_frametype_experimental;
+      break;
+
+    default:
+      frametype = &id3_frametype_unknown;
+      if (id3_compat_lookup(id, 4))
+	frametype = &id3_frametype_obsolete;
+      break;
+    }
+  }
+
+  frame = malloc(sizeof(*frame) + frametype->nfields * sizeof(*frame->fields));
+  if (frame) {
+    frame->id[0] = id[0];
+    frame->id[1] = id[1];
+    frame->id[2] = id[2];
+    frame->id[3] = id[3];
+    frame->id[4] = 0;
+
+    frame->description       = frametype->description;
+    frame->refcount          = 0;
+    frame->flags             = frametype->defaultflags;
+    frame->group_id          = 0;
+    frame->encryption_method = 0;
+    frame->encoded           = 0;
+    frame->encoded_length    = 0;
+    frame->decoded_length    = 0;
+    frame->nfields           = frametype->nfields;
+    frame->fields            = (union id3_field *) &frame[1];
+
+    for (i = 0; i < frame->nfields; ++i)
+      id3_field_init(&frame->fields[i], frametype->fields[i]);
+  }
+
+  return frame;
+}
+
+void id3_frame_delete(struct id3_frame *frame)
+{
+  assert(frame);
+
+  if (frame->refcount == 0) {
+    unsigned int i;
+
+    for (i = 0; i < frame->nfields; ++i)
+      id3_field_finish(&frame->fields[i]);
+
+    if (frame->encoded)
+      free(frame->encoded);
+
+    free(frame);
+  }
+}
+
+/*
+ * NAME:	frame->addref()
+ * DESCRIPTION:	add an external reference to a frame
+ */
+void id3_frame_addref(struct id3_frame *frame)
+{
+  assert(frame);
+
+  ++frame->refcount;
+}
+
+/*
+ * NAME:	frame->delref()
+ * DESCRIPTION:	remove an external reference to a frame
+ */
+void id3_frame_delref(struct id3_frame *frame)
+{
+  assert(frame && frame->refcount > 0);
+
+  --frame->refcount;
+}
+
+/*
+ * NAME:	frame->field()
+ * DESCRIPTION:	return a pointer to a field in a frame
+ */
+union id3_field *id3_frame_field(struct id3_frame const *frame,
+				 unsigned int index)
+{
+  assert(frame);
+
+  return (index < frame->nfields) ? &frame->fields[index] : 0;
+}
+
+static
+struct id3_frame *obsolete(char const *id, id3_byte_t const *data,
+			   id3_length_t length)
+{
+  struct id3_frame *frame;
+
+  frame = id3_frame_new(ID3_FRAME_OBSOLETE);
+  if (frame) {
+    if (id3_field_setframeid(&frame->fields[0], id) == -1 ||
+	id3_field_setbinarydata(&frame->fields[1], data, length) == -1)
+      goto fail;
+  }
+
+  if (0) {
+  fail:
+    if (frame) {
+      id3_frame_delete(frame);
+      frame = 0;
+    }
+  }
+
+  return frame;
+}
+
+static
+struct id3_frame *unparseable(char const *id, id3_byte_t const **ptr,
+			      id3_length_t length, int flags,
+			      int group_id, int encryption_method,
+			      id3_length_t decoded_length)
+{
+  struct id3_frame *frame = 0;
+  id3_byte_t *mem;
+
+  mem = malloc(length ? length : 1);
+  if (mem == 0)
+    goto fail;
+
+  frame = id3_frame_new(id);
+  if (frame == 0)
+    free(mem);
+  else {
+    memcpy(mem, *ptr, length);
+
+    frame->flags             = flags;
+    frame->group_id          = group_id;
+    frame->encryption_method = encryption_method;
+    frame->encoded           = mem;
+    frame->encoded_length    = length;
+    frame->decoded_length    = decoded_length;
+  }
+
+  if (0) {
+  fail:
+    ;
+  }
+
+  *ptr += length;
+
+  return frame;
+}
+
+static
+int parse_data(struct id3_frame *frame,
+	       id3_byte_t const *data, id3_length_t length)
+{
+  enum id3_field_textencoding encoding;
+  id3_byte_t const *end;
+  unsigned int i;
+
+  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
+
+  end = data + length;
+
+  for (i = 0; i < frame->nfields; ++i) {
+    if (id3_field_parse(&frame->fields[i], &data, end - data, &encoding) == -1)
+      return -1;
+  }
+
+  return 0;
+}
+
+/*
+ * NAME:	frame->parse()
+ * DESCRIPTION:	parse raw frame data according to the specified ID3 tag version
+ */
+struct id3_frame *id3_frame_parse(id3_byte_t const **ptr, id3_length_t length,
+				  unsigned int version)
+{
+  struct id3_frame *frame = 0;
+  id3_byte_t const *id, *end, *data;
+  id3_length_t size, decoded_length = 0;
+  int flags = 0, group_id = 0, encryption_method = 0;
+  struct id3_compat const *compat = 0;
+  id3_byte_t *mem = 0;
+  char xid[4];
+
+  id  = *ptr;
+  end = *ptr + length;
+
+  if (ID3_TAG_VERSION_MAJOR(version) < 4) {
+    switch (ID3_TAG_VERSION_MAJOR(version)) {
+    case 2:
+      if (length < 6)
+	goto fail;
+
+      compat = id3_compat_lookup(id, 3);
+
+      *ptr += 3;
+      size  = id3_parse_uint(ptr, 3);
+
+      if (size > end - *ptr)
+	goto fail;
+
+      end = *ptr + size;
+
+      break;
+
+    case 3:
+      if (length < 10)
+	goto fail;
+
+      compat = id3_compat_lookup(id, 4);
+
+      *ptr += 4;
+      size  = id3_parse_uint(ptr, 4);
+      flags = id3_parse_uint(ptr, 2);
+
+      if (size > end - *ptr)
+	goto fail;
+
+      end = *ptr + size;
+
+      if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~0x00e0)) {
+	frame = unparseable(id, ptr, end - *ptr, 0, 0, 0, 0);
+	goto done;
+      }
+
+      flags =
+	((flags >> 1) & ID3_FRAME_FLAG_STATUSFLAGS) |
+	((flags >> 4) & (ID3_FRAME_FLAG_COMPRESSION |
+			 ID3_FRAME_FLAG_ENCRYPTION)) |
+	((flags << 1) & ID3_FRAME_FLAG_GROUPINGIDENTITY);
+
+      if (flags & ID3_FRAME_FLAG_COMPRESSION) {
+	if (end - *ptr < 4)
+	  goto fail;
+
+	decoded_length = id3_parse_uint(ptr, 4);
+      }
+
+      if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
+	if (end - *ptr < 1)
+	  goto fail;
+
+	encryption_method = id3_parse_uint(ptr, 1);
+      }
+
+      if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {
+	if (end - *ptr < 1)
+	  goto fail;
+
+	group_id = id3_parse_uint(ptr, 1);
+      }
+
+      break;
+
+    default:
+      goto fail;
+    }
+
+    /* canonicalize frame ID for ID3v2.4 */
+
+    if (compat && compat->equiv)
+      id = compat->equiv;
+    else if (ID3_TAG_VERSION_MAJOR(version) == 2) {
+      xid[0] = 'Y';
+      xid[1] = id[0];
+      xid[2] = id[1];
+      xid[3] = id[2];
+
+      id = xid;
+
+      flags |=
+	ID3_FRAME_FLAG_TAGALTERPRESERVATION |
+	ID3_FRAME_FLAG_FILEALTERPRESERVATION;
+    }
+  }
+  else {  /* ID3v2.4 */
+    if (length < 10)
+      goto fail;
+
+    *ptr += 4;
+    size  = id3_parse_syncsafe(ptr, 4);
+    flags = id3_parse_uint(ptr, 2);
+
+    if (size > end - *ptr)
+      goto fail;
+
+    end = *ptr + size;
+
+    if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) {
+      frame = unparseable(id, ptr, end - *ptr, flags, 0, 0, 0);
+      goto done;
+    }
+
+    if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) {
+      if (end - *ptr < 1)
+	goto fail;
+
+      group_id = id3_parse_uint(ptr, 1);
+    }
+
+    if ((flags & ID3_FRAME_FLAG_COMPRESSION) &&
+	!(flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR))
+      goto fail;
+
+    if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
+      if (end - *ptr < 1)
+	goto fail;
+
+      encryption_method = id3_parse_uint(ptr, 1);
+    }
+
+    if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {
+      if (end - *ptr < 4)
+	goto fail;
+
+      decoded_length = id3_parse_syncsafe(ptr, 4);
+    }
+  }
+
+  data = *ptr;
+  *ptr = end;
+
+  /* undo frame encodings */
+
+  if ((flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) && end - data > 0) {
+    mem = malloc(end - data);
+    if (mem == 0)
+      goto fail;
+
+    memcpy(mem, data, end - data);
+
+    end  = mem + id3_util_deunsynchronise(mem, end - data);
+    data = mem;
+  }
+
+  if (flags & ID3_FRAME_FLAG_ENCRYPTION) {
+    frame = unparseable(id, &data, end - data, flags,
+			group_id, encryption_method, decoded_length);
+    goto done;
+  }
+
+  if (flags & ID3_FRAME_FLAG_COMPRESSION) {
+    id3_byte_t *decomp;
+
+    decomp = id3_util_decompress(data, end - data, decoded_length);
+    if (decomp == 0)
+      goto fail;
+
+    if (mem)
+      free(mem);
+
+    data = mem = decomp;
+    end  = data + decoded_length;
+  }
+
+  /* check for obsolescence */
+
+  if (compat && !compat->equiv) {
+    frame = obsolete(id, data, end - data);
+    goto done;
+  }
+
+  /* generate the internal frame structure */
+
+  frame = id3_frame_new(id);
+  if (frame) {
+    frame->flags    = flags;
+    frame->group_id = group_id;
+
+    if (compat && compat->translate) {
+      if (compat->translate(frame, compat->id, data, end - data) == -1)
+	goto fail;
+    }
+    else {
+      if (parse_data(frame, data, end - data) == -1)
+	goto fail;
+    }
+  }
+
+  if (0) {
+  fail:
+    if (frame) {
+      id3_frame_delete(frame);
+      frame = 0;
+    }
+  }
+
+ done:
+  if (mem)
+    free(mem);
+
+  return frame;
+}
+
+static
+id3_length_t render_data(id3_byte_t **ptr,
+			 union id3_field *fields, unsigned int length)
+{
+  id3_length_t size = 0;
+  enum id3_field_textencoding encoding;
+  unsigned int i;
+
+  encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; //here!! --yaz
+  printf("frame.c: render_data: encoding = %d\n", encoding);
+  fflush(NULL);
+  for (i = 0; i < length; ++i)
+    size += id3_field_render(&fields[i], ptr, &encoding, i < length - 1);
+
+  return size;
+}
+
+/*
+ * NAME:	frame->render()
+ * DESCRIPTION:	render a single, complete frame
+ */
+id3_length_t id3_frame_render(struct id3_frame const *frame,
+			      id3_byte_t **ptr, int options)
+{
+  id3_length_t size = 0, decoded_length, datalen;
+  id3_byte_t *size_ptr = 0, *flags_ptr = 0, *data = 0;
+  int flags;
+
+  assert(frame);
+
+  if ((frame->flags & ID3_FRAME_FLAG_TAGALTERPRESERVATION) ||
+      ((options & ID3_TAG_OPTION_FILEALTERED) &&
+       (frame->flags & ID3_FRAME_FLAG_FILEALTERPRESERVATION)))
+    return 0;
+
+  /* a frame must be at least 1 byte big, excluding the header */
+
+  decoded_length = render_data(0, frame->fields, frame->nfields);
+  if (decoded_length == 0 && frame->encoded == 0)
+    return 0;
+
+  /* header */
+
+  size += id3_render_immediate(ptr, frame->id, 4);
+
+  if (ptr)
+    size_ptr = *ptr;
+
+  size += id3_render_syncsafe(ptr, 0, 4);
+
+  if (ptr)
+    flags_ptr = *ptr;
+
+  flags = frame->flags;
+
+  size += id3_render_int(ptr, flags, 2);
+
+  if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) {
+    size += id3_render_binary(ptr, frame->encoded, frame->encoded_length);
+    if (size_ptr)
+      id3_render_syncsafe(&size_ptr, size - 10, 4);
+
+    return size;
+  }
+
+  flags &= ID3_FRAME_FLAG_KNOWNFLAGS;
+
+  flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;
+  if (options & ID3_TAG_OPTION_UNSYNCHRONISATION)
+    flags |= ID3_FRAME_FLAG_UNSYNCHRONISATION;
+
+  if (!(flags & ID3_FRAME_FLAG_ENCRYPTION)) {
+    flags &= ~ID3_FRAME_FLAG_COMPRESSION;
+    if (options & ID3_TAG_OPTION_COMPRESSION)
+      flags |= ID3_FRAME_FLAG_COMPRESSION | ID3_FRAME_FLAG_DATALENGTHINDICATOR;
+  }
+
+  if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY)
+    size += id3_render_int(ptr, frame->group_id, 1);
+  if (flags & ID3_FRAME_FLAG_ENCRYPTION)
+    size += id3_render_int(ptr, frame->encryption_method, 1);
+  if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) {
+    if (flags & ID3_FRAME_FLAG_ENCRYPTION)
+      decoded_length = frame->decoded_length;
+    size += id3_render_syncsafe(ptr, decoded_length, 4);
+  }
+
+  if (ptr)
+    data = *ptr;
+
+  if (flags & ID3_FRAME_FLAG_ENCRYPTION)
+    datalen = id3_render_binary(ptr, frame->encoded, frame->encoded_length);
+  else {
+    if (ptr == 0)
+      datalen = decoded_length;
+    else {
+      datalen = render_data(ptr, frame->fields, frame->nfields);
+
+      if (flags & ID3_FRAME_FLAG_COMPRESSION) {
+	id3_byte_t *comp;
+	id3_length_t complen;
+
+	comp = id3_util_compress(data, datalen, &complen);
+	if (comp == 0)
+	  flags &= ~ID3_FRAME_FLAG_COMPRESSION;
+	else {
+	  *ptr = data;
+	  datalen = id3_render_binary(ptr, comp, complen);
+
+	  free(comp);
+	}
+      }
+    }
+  }
+
+  /* unsynchronisation */
+
+  if (flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) {
+    if (data == 0)
+      datalen *= 2;
+    else {
+      id3_length_t newlen;
+
+      newlen = id3_util_unsynchronise(data, datalen);
+      if (newlen == datalen)
+	flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION;
+      else {
+	*ptr   += newlen - datalen;
+	datalen = newlen;
+      }
+    }
+  }
+
+  size += datalen;
+
+  /* patch size and flags */
+
+  if (size_ptr)
+    id3_render_syncsafe(&size_ptr, size - 10, 4);
+  if (flags_ptr)
+    id3_render_int(&flags_ptr, flags, 2);
+
+  return size;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/frame.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,36 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: frame.h,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_FRAME_H
+# define LIBID3TAG_FRAME_H
+
+# include "id3tag.h"
+
+int id3_frame_validid(char const *);
+
+void id3_frame_addref(struct id3_frame *);
+void id3_frame_delref(struct id3_frame *);
+
+struct id3_frame *id3_frame_parse(id3_byte_t const **, id3_length_t,
+				  unsigned int);
+id3_length_t id3_frame_render(struct id3_frame const *, id3_byte_t **, int);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/frametype.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,568 @@
+/* C code produced by gperf version 3.0.1 */
+/* Command-line: gperf -tCcTonD -K id -N id3_frametype_lookup -s -3 -k '*' frametype.gperf  */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 1 "frametype.gperf"
+
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * Id: frametype.gperf,v 1.7 2004/01/23 09:41:32 rob Exp 
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <string.h>
+
+# include "id3tag.h"
+# include "frametype.h"
+
+# define FIELDS(id)  static enum id3_field_type const fields_##id[]
+
+/* frame field descriptions */
+
+FIELDS(UFID) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(TXXX) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRING
+};
+
+FIELDS(WXXX) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_LATIN1
+};
+
+FIELDS(MCDI) = {
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(ETCO) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(MLLT) = {
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT24,
+  ID3_FIELD_TYPE_INT24,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(SYTC) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(USLT) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRINGFULL
+};
+
+FIELDS(SYLT) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(COMM) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRINGFULL
+};
+
+FIELDS(RVA2) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(EQU2) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(RVRB) = {
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8
+};
+
+FIELDS(APIC) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(GEOB) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(PCNT) = {
+  ID3_FIELD_TYPE_INT32PLUS
+};
+
+FIELDS(POPM) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT32PLUS
+};
+
+FIELDS(RBUF) = {
+  ID3_FIELD_TYPE_INT24,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT32
+};
+
+FIELDS(AENC) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(LINK) = {
+  ID3_FIELD_TYPE_FRAMEID,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_LATIN1LIST
+};
+
+FIELDS(POSS) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(USER) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_STRING
+};
+
+FIELDS(OWNE) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_DATE,
+  ID3_FIELD_TYPE_STRING
+};
+
+FIELDS(COMR) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_DATE,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(ENCR) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(GRID) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(PRIV) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(SIGN) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(SEEK) = {
+  ID3_FIELD_TYPE_INT32
+};
+
+FIELDS(ASPI) = {
+  ID3_FIELD_TYPE_INT32,
+  ID3_FIELD_TYPE_INT32,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(text) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_STRINGLIST
+};
+
+FIELDS(url) = {
+  ID3_FIELD_TYPE_LATIN1
+};
+
+FIELDS(unknown) = {
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(ZOBS) = {
+  ID3_FIELD_TYPE_FRAMEID,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+# define FRAME(id)  \
+  sizeof(fields_##id) / sizeof(fields_##id[0]), fields_##id
+
+# define PRESERVE  0
+# define DISCARD   ID3_FRAME_FLAG_FILEALTERPRESERVATION
+# define OBSOLETE  (DISCARD | ID3_FRAME_FLAG_TAGALTERPRESERVATION)
+
+# define FRAMETYPE(type, id, flags, desc)  \
+  struct id3_frametype const id3_frametype_##type = {  \
+    0, FRAME(id), flags, desc  \
+  }
+
+/* static frame types */
+
+FRAMETYPE(text,         text,    PRESERVE, "Unknown text information frame");
+FRAMETYPE(url,          url,     PRESERVE, "Unknown URL link frame");
+FRAMETYPE(experimental, unknown, PRESERVE, "Experimental frame");
+FRAMETYPE(unknown,      unknown, PRESERVE, "Unknown frame");
+FRAMETYPE(obsolete,     unknown, OBSOLETE, "Obsolete frame");
+
+#define TOTAL_KEYWORDS 84
+#define MIN_WORD_LENGTH 4
+#define MAX_WORD_LENGTH 4
+#define MIN_HASH_VALUE 7
+#define MAX_HASH_VALUE 155
+/* maximum key range = 149, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (str, len)
+     register const char *str;
+     register unsigned int len;
+{
+  static const unsigned char asso_values[] =
+    {
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+       43,   4,  47,  49, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156,  31,  53,   3,  15,   3,
+       24,  25,  10,  52,  69,  34,  23,  30,   1,   5,
+       10,  62,  20,   0,  28,  28,  22,  19,  47,   3,
+       10, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+      156, 156, 156, 156, 156, 156, 156
+    };
+  return asso_values[(unsigned char)str[3]+1] + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
+}
+
+#ifdef __GNUC__
+__inline
+#endif
+const struct id3_frametype *
+id3_frametype_lookup (str, len)
+     register const char *str;
+     register unsigned int len;
+{
+  static const struct id3_frametype wordlist[] =
+    {
+#line 282 "frametype.gperf"
+      {"ENCR", FRAME(ENCR), PRESERVE, "Encryption method registration"},
+#line 292 "frametype.gperf"
+      {"POPM", FRAME(POPM), PRESERVE, "Popularimeter"},
+#line 351 "frametype.gperf"
+      {"WCOM", FRAME(url),  PRESERVE, "Commercial information"},
+#line 298 "frametype.gperf"
+      {"SEEK", FRAME(SEEK), DISCARD,  "Seek frame"},
+#line 349 "frametype.gperf"
+      {"USER", FRAME(USER), PRESERVE, "Terms of use"},
+#line 285 "frametype.gperf"
+      {"GEOB", FRAME(GEOB), PRESERVE, "General encapsulated object"},
+#line 304 "frametype.gperf"
+      {"TCOM", FRAME(text), PRESERVE, "Composer"},
+#line 281 "frametype.gperf"
+      {"COMR", FRAME(COMR), PRESERVE, "Commercial frame"},
+#line 280 "frametype.gperf"
+      {"COMM", FRAME(COMM), PRESERVE, "Comments"},
+#line 305 "frametype.gperf"
+      {"TCON", FRAME(text), PRESERVE, "Content type"},
+#line 291 "frametype.gperf"
+      {"PCNT", FRAME(PCNT), PRESERVE, "Play counter"},
+#line 293 "frametype.gperf"
+      {"POSS", FRAME(POSS), DISCARD,  "Position synchronisation frame"},
+#line 284 "frametype.gperf"
+      {"ETCO", FRAME(ETCO), DISCARD,  "Event timing codes"},
+#line 332 "frametype.gperf"
+      {"TPE2", FRAME(text), PRESERVE, "Band/orchestra/accompaniment"},
+#line 301 "frametype.gperf"
+      {"SYTC", FRAME(SYTC), DISCARD,  "Synchronised tempo codes"},
+#line 313 "frametype.gperf"
+      {"TENC", FRAME(text), DISCARD,  "Encoded by"},
+#line 309 "frametype.gperf"
+      {"TDOR", FRAME(text), PRESERVE, "Original release time"},
+#line 290 "frametype.gperf"
+      {"OWNE", FRAME(OWNE), PRESERVE, "Ownership frame"},
+#line 277 "frametype.gperf"
+      {"AENC", FRAME(AENC), DISCARD,  "Audio encryption"},
+#line 307 "frametype.gperf"
+      {"TDEN", FRAME(text), PRESERVE, "Encoding time"},
+#line 345 "frametype.gperf"
+      {"TSSE", FRAME(text), PRESERVE, "Software/hardware and settings used for encoding"},
+#line 339 "frametype.gperf"
+      {"TRSN", FRAME(text), PRESERVE, "Internet radio station name"},
+#line 300 "frametype.gperf"
+      {"SYLT", FRAME(SYLT), DISCARD,  "Synchronised lyric/text"},
+#line 354 "frametype.gperf"
+      {"WOAR", FRAME(url),  PRESERVE, "Official artist/performer webpage"},
+#line 346 "frametype.gperf"
+      {"TSST", FRAME(text), PRESERVE, "Set subtitle"},
+#line 330 "frametype.gperf"
+      {"TOWN", FRAME(text), PRESERVE, "File owner/licensee"},
+#line 340 "frametype.gperf"
+      {"TRSO", FRAME(text), PRESERVE, "Internet radio station owner"},
+#line 322 "frametype.gperf"
+      {"TLEN", FRAME(text), DISCARD,  "Length"},
+#line 358 "frametype.gperf"
+      {"WPUB", FRAME(url),  PRESERVE, "Publishers official webpage"},
+#line 343 "frametype.gperf"
+      {"TSOT", FRAME(text), PRESERVE, "Title sort order"},
+#line 327 "frametype.gperf"
+      {"TOFN", FRAME(text), PRESERVE, "Original filename"},
+#line 344 "frametype.gperf"
+      {"TSRC", FRAME(text), PRESERVE, "ISRC (international standard recording code)"},
+#line 324 "frametype.gperf"
+      {"TMED", FRAME(text), PRESERVE, "Media type"},
+#line 297 "frametype.gperf"
+      {"RVRB", FRAME(RVRB), PRESERVE, "Reverb"},
+#line 328 "frametype.gperf"
+      {"TOLY", FRAME(text), PRESERVE, "Original lyricist(s)/text writer(s)"},
+#line 329 "frametype.gperf"
+      {"TOPE", FRAME(text), PRESERVE, "Original artist(s)/performer(s)"},
+#line 336 "frametype.gperf"
+      {"TPRO", FRAME(text), PRESERVE, "Produced notice"},
+#line 337 "frametype.gperf"
+      {"TPUB", FRAME(text), PRESERVE, "Publisher"},
+#line 357 "frametype.gperf"
+      {"WPAY", FRAME(url),  PRESERVE, "Payment"},
+#line 335 "frametype.gperf"
+      {"TPOS", FRAME(text), PRESERVE, "Part of a set"},
+#line 356 "frametype.gperf"
+      {"WORS", FRAME(url),  PRESERVE, "Official Internet radio station homepage"},
+#line 325 "frametype.gperf"
+      {"TMOO", FRAME(text), PRESERVE, "Mood"},
+#line 338 "frametype.gperf"
+      {"TRCK", FRAME(text), PRESERVE, "Track number/position in set"},
+#line 320 "frametype.gperf"
+      {"TKEY", FRAME(text), PRESERVE, "Initial key"},
+#line 308 "frametype.gperf"
+      {"TDLY", FRAME(text), PRESERVE, "Playlist delay"},
+#line 296 "frametype.gperf"
+      {"RVA2", FRAME(RVA2), DISCARD,  "Relative volume adjustment (2)"},
+#line 310 "frametype.gperf"
+      {"TDRC", FRAME(text), PRESERVE, "Recording time"},
+#line 350 "frametype.gperf"
+      {"USLT", FRAME(USLT), PRESERVE, "Unsynchronised lyric/text transcription"},
+#line 353 "frametype.gperf"
+      {"WOAF", FRAME(url),  PRESERVE, "Official audio file webpage"},
+#line 312 "frametype.gperf"
+      {"TDTG", FRAME(text), PRESERVE, "Tagging time"},
+#line 299 "frametype.gperf"
+      {"SIGN", FRAME(SIGN), PRESERVE, "Signature frame"},
+#line 355 "frametype.gperf"
+      {"WOAS", FRAME(url),  PRESERVE, "Official audio source webpage"},
+#line 331 "frametype.gperf"
+      {"TPE1", FRAME(text), PRESERVE, "Lead performer(s)/soloist(s)"},
+#line 302 "frametype.gperf"
+      {"TALB", FRAME(text), PRESERVE, "Album/movie/show title"},
+#line 341 "frametype.gperf"
+      {"TSOA", FRAME(text), PRESERVE, "Album sort order"},
+#line 321 "frametype.gperf"
+      {"TLAN", FRAME(text), PRESERVE, "Language(s)"},
+#line 333 "frametype.gperf"
+      {"TPE3", FRAME(text), PRESERVE, "Conductor/performer refinement"},
+#line 352 "frametype.gperf"
+      {"WCOP", FRAME(url),  PRESERVE, "Copyright/legal information"},
+#line 334 "frametype.gperf"
+      {"TPE4", FRAME(text), PRESERVE, "Interpreted, remixed, or otherwise modified by"},
+#line 323 "frametype.gperf"
+      {"TMCL", FRAME(text), PRESERVE, "Musician credits list"},
+#line 303 "frametype.gperf"
+      {"TBPM", FRAME(text), PRESERVE, "BPM (beats per minute)"},
+#line 311 "frametype.gperf"
+      {"TDRL", FRAME(text), PRESERVE, "Release time"},
+#line 326 "frametype.gperf"
+      {"TOAL", FRAME(text), PRESERVE, "Original album/movie/show title"},
+#line 342 "frametype.gperf"
+      {"TSOP", FRAME(text), PRESERVE, "Performer sort order"},
+#line 363 "frametype.gperf"
+      {"ZOBS", FRAME(ZOBS), OBSOLETE, "Obsolete frame"},
+#line 283 "frametype.gperf"
+      {"EQU2", FRAME(EQU2), DISCARD,  "Equalisation (2)"},
+#line 306 "frametype.gperf"
+      {"TCOP", FRAME(text), PRESERVE, "Copyright message"},
+#line 287 "frametype.gperf"
+      {"LINK", FRAME(LINK), PRESERVE, "Linked information"},
+#line 286 "frametype.gperf"
+      {"GRID", FRAME(GRID), PRESERVE, "Group identification registration"},
+#line 294 "frametype.gperf"
+      {"PRIV", FRAME(PRIV), PRESERVE, "Private frame"},
+#line 315 "frametype.gperf"
+      {"TFLT", FRAME(text), PRESERVE, "File type"},
+#line 289 "frametype.gperf"
+      {"MLLT", FRAME(MLLT), DISCARD,  "MPEG location lookup table"},
+#line 314 "frametype.gperf"
+      {"TEXT", FRAME(text), PRESERVE, "Lyricist/text writer"},
+#line 348 "frametype.gperf"
+      {"UFID", FRAME(UFID), PRESERVE, "Unique file identifier"},
+#line 278 "frametype.gperf"
+      {"APIC", FRAME(APIC), PRESERVE, "Attached picture"},
+#line 279 "frametype.gperf"
+      {"ASPI", FRAME(ASPI), DISCARD,  "Audio seek point index"},
+#line 318 "frametype.gperf"
+      {"TIT2", FRAME(text), PRESERVE, "Title/songname/content description"},
+#line 359 "frametype.gperf"
+      {"WXXX", FRAME(WXXX), PRESERVE, "User defined URL link frame"},
+#line 288 "frametype.gperf"
+      {"MCDI", FRAME(MCDI), PRESERVE, "Music CD identifier"},
+#line 316 "frametype.gperf"
+      {"TIPL", FRAME(text), PRESERVE, "Involved people list"},
+#line 347 "frametype.gperf"
+      {"TXXX", FRAME(TXXX), PRESERVE, "User defined text information frame"},
+#line 295 "frametype.gperf"
+      {"RBUF", FRAME(RBUF), PRESERVE, "Recommended buffer size"},
+#line 317 "frametype.gperf"
+      {"TIT1", FRAME(text), PRESERVE, "Content group description"},
+#line 319 "frametype.gperf"
+      {"TIT3", FRAME(text), PRESERVE, "Subtitle/description refinement"}
+    };
+
+  static const short lookup[] =
+    {
+      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  1, -1,
+       2,  3, -1,  4, -1, -1, -1, -1,  5,  6,  7,  8, -1,  9,
+      10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+      24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+      38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+      66, 67, 68, 69, -1, 70, 71, -1, 72, 73, 74, -1, 75, -1,
+      76, -1, -1, -1, 77, 78, -1, -1, 79, -1, -1, -1, -1, 80,
+      81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1,
+      -1, 83
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int index = lookup[key];
+
+          if (index >= 0)
+            {
+              register const char *s = wordlist[index].id;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[index];
+            }
+        }
+    }
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/frametype.gperf	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,363 @@
+%{
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: frametype.gperf,v 1.7 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <string.h>
+
+# include "id3tag.h"
+# include "frametype.h"
+
+# define FIELDS(id)  static enum id3_field_type const fields_##id[]
+
+/* frame field descriptions */
+
+FIELDS(UFID) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(TXXX) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRING
+};
+
+FIELDS(WXXX) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_LATIN1
+};
+
+FIELDS(MCDI) = {
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(ETCO) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(MLLT) = {
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT24,
+  ID3_FIELD_TYPE_INT24,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(SYTC) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(USLT) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRINGFULL
+};
+
+FIELDS(SYLT) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(COMM) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRINGFULL
+};
+
+FIELDS(RVA2) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(EQU2) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(RVRB) = {
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT8
+};
+
+FIELDS(APIC) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(GEOB) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(PCNT) = {
+  ID3_FIELD_TYPE_INT32PLUS
+};
+
+FIELDS(POPM) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT32PLUS
+};
+
+FIELDS(RBUF) = {
+  ID3_FIELD_TYPE_INT24,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT32
+};
+
+FIELDS(AENC) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(LINK) = {
+  ID3_FIELD_TYPE_FRAMEID,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_LATIN1LIST
+};
+
+FIELDS(POSS) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(USER) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_STRING
+};
+
+FIELDS(OWNE) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_DATE,
+  ID3_FIELD_TYPE_STRING
+};
+
+FIELDS(COMR) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_DATE,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(ENCR) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(GRID) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(PRIV) = {
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(SIGN) = {
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(SEEK) = {
+  ID3_FIELD_TYPE_INT32
+};
+
+FIELDS(ASPI) = {
+  ID3_FIELD_TYPE_INT32,
+  ID3_FIELD_TYPE_INT32,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(text) = {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_STRINGLIST
+};
+
+FIELDS(url) = {
+  ID3_FIELD_TYPE_LATIN1
+};
+
+FIELDS(unknown) = {
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+FIELDS(ZOBS) = {
+  ID3_FIELD_TYPE_FRAMEID,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+# define FRAME(id)  \
+  sizeof(fields_##id) / sizeof(fields_##id[0]), fields_##id
+
+# define PRESERVE  0
+# define DISCARD   ID3_FRAME_FLAG_FILEALTERPRESERVATION
+# define OBSOLETE  (DISCARD | ID3_FRAME_FLAG_TAGALTERPRESERVATION)
+
+# define FRAMETYPE(type, id, flags, desc)  \
+  struct id3_frametype const id3_frametype_##type = {  \
+    0, FRAME(id), flags, desc  \
+  }
+
+/* static frame types */
+
+FRAMETYPE(text,         text,    PRESERVE, "Unknown text information frame");
+FRAMETYPE(url,          url,     PRESERVE, "Unknown URL link frame");
+FRAMETYPE(experimental, unknown, PRESERVE, "Experimental frame");
+FRAMETYPE(unknown,      unknown, PRESERVE, "Unknown frame");
+FRAMETYPE(obsolete,     unknown, OBSOLETE, "Obsolete frame");
+%}
+struct id3_frametype;
+%%
+#
+# ID3v2.4 frames
+#
+AENC, FRAME(AENC), DISCARD,  "Audio encryption"
+APIC, FRAME(APIC), PRESERVE, "Attached picture"
+ASPI, FRAME(ASPI), DISCARD,  "Audio seek point index"
+COMM, FRAME(COMM), PRESERVE, "Comments"
+COMR, FRAME(COMR), PRESERVE, "Commercial frame"
+ENCR, FRAME(ENCR), PRESERVE, "Encryption method registration"
+EQU2, FRAME(EQU2), DISCARD,  "Equalisation (2)"
+ETCO, FRAME(ETCO), DISCARD,  "Event timing codes"
+GEOB, FRAME(GEOB), PRESERVE, "General encapsulated object"
+GRID, FRAME(GRID), PRESERVE, "Group identification registration"
+LINK, FRAME(LINK), PRESERVE, "Linked information"
+MCDI, FRAME(MCDI), PRESERVE, "Music CD identifier"
+MLLT, FRAME(MLLT), DISCARD,  "MPEG location lookup table"
+OWNE, FRAME(OWNE), PRESERVE, "Ownership frame"
+PCNT, FRAME(PCNT), PRESERVE, "Play counter"
+POPM, FRAME(POPM), PRESERVE, "Popularimeter"
+POSS, FRAME(POSS), DISCARD,  "Position synchronisation frame"
+PRIV, FRAME(PRIV), PRESERVE, "Private frame"
+RBUF, FRAME(RBUF), PRESERVE, "Recommended buffer size"
+RVA2, FRAME(RVA2), DISCARD,  "Relative volume adjustment (2)"
+RVRB, FRAME(RVRB), PRESERVE, "Reverb"
+SEEK, FRAME(SEEK), DISCARD,  "Seek frame"
+SIGN, FRAME(SIGN), PRESERVE, "Signature frame"
+SYLT, FRAME(SYLT), DISCARD,  "Synchronised lyric/text"
+SYTC, FRAME(SYTC), DISCARD,  "Synchronised tempo codes"
+TALB, FRAME(text), PRESERVE, "Album/movie/show title"
+TBPM, FRAME(text), PRESERVE, "BPM (beats per minute)"
+TCOM, FRAME(text), PRESERVE, "Composer"
+TCON, FRAME(text), PRESERVE, "Content type"
+TCOP, FRAME(text), PRESERVE, "Copyright message"
+TDEN, FRAME(text), PRESERVE, "Encoding time"
+TDLY, FRAME(text), PRESERVE, "Playlist delay"
+TDOR, FRAME(text), PRESERVE, "Original release time"
+TDRC, FRAME(text), PRESERVE, "Recording time"
+TDRL, FRAME(text), PRESERVE, "Release time"
+TDTG, FRAME(text), PRESERVE, "Tagging time"
+TENC, FRAME(text), DISCARD,  "Encoded by"
+TEXT, FRAME(text), PRESERVE, "Lyricist/text writer"
+TFLT, FRAME(text), PRESERVE, "File type"
+TIPL, FRAME(text), PRESERVE, "Involved people list"
+TIT1, FRAME(text), PRESERVE, "Content group description"
+TIT2, FRAME(text), PRESERVE, "Title/songname/content description"
+TIT3, FRAME(text), PRESERVE, "Subtitle/description refinement"
+TKEY, FRAME(text), PRESERVE, "Initial key"
+TLAN, FRAME(text), PRESERVE, "Language(s)"
+TLEN, FRAME(text), DISCARD,  "Length"
+TMCL, FRAME(text), PRESERVE, "Musician credits list"
+TMED, FRAME(text), PRESERVE, "Media type"
+TMOO, FRAME(text), PRESERVE, "Mood"
+TOAL, FRAME(text), PRESERVE, "Original album/movie/show title"
+TOFN, FRAME(text), PRESERVE, "Original filename"
+TOLY, FRAME(text), PRESERVE, "Original lyricist(s)/text writer(s)"
+TOPE, FRAME(text), PRESERVE, "Original artist(s)/performer(s)"
+TOWN, FRAME(text), PRESERVE, "File owner/licensee"
+TPE1, FRAME(text), PRESERVE, "Lead performer(s)/soloist(s)"
+TPE2, FRAME(text), PRESERVE, "Band/orchestra/accompaniment"
+TPE3, FRAME(text), PRESERVE, "Conductor/performer refinement"
+TPE4, FRAME(text), PRESERVE, "Interpreted, remixed, or otherwise modified by"
+TPOS, FRAME(text), PRESERVE, "Part of a set"
+TPRO, FRAME(text), PRESERVE, "Produced notice"
+TPUB, FRAME(text), PRESERVE, "Publisher"
+TRCK, FRAME(text), PRESERVE, "Track number/position in set"
+TRSN, FRAME(text), PRESERVE, "Internet radio station name"
+TRSO, FRAME(text), PRESERVE, "Internet radio station owner"
+TSOA, FRAME(text), PRESERVE, "Album sort order"
+TSOP, FRAME(text), PRESERVE, "Performer sort order"
+TSOT, FRAME(text), PRESERVE, "Title sort order"
+TSRC, FRAME(text), PRESERVE, "ISRC (international standard recording code)"
+TSSE, FRAME(text), PRESERVE, "Software/hardware and settings used for encoding"
+TSST, FRAME(text), PRESERVE, "Set subtitle"
+TXXX, FRAME(TXXX), PRESERVE, "User defined text information frame"
+UFID, FRAME(UFID), PRESERVE, "Unique file identifier"
+USER, FRAME(USER), PRESERVE, "Terms of use"
+USLT, FRAME(USLT), PRESERVE, "Unsynchronised lyric/text transcription"
+WCOM, FRAME(url),  PRESERVE, "Commercial information"
+WCOP, FRAME(url),  PRESERVE, "Copyright/legal information"
+WOAF, FRAME(url),  PRESERVE, "Official audio file webpage"
+WOAR, FRAME(url),  PRESERVE, "Official artist/performer webpage"
+WOAS, FRAME(url),  PRESERVE, "Official audio source webpage"
+WORS, FRAME(url),  PRESERVE, "Official Internet radio station homepage"
+WPAY, FRAME(url),  PRESERVE, "Payment"
+WPUB, FRAME(url),  PRESERVE, "Publishers official webpage"
+WXXX, FRAME(WXXX), PRESERVE, "User defined URL link frame"
+#
+# Special frames
+#
+ZOBS, FRAME(ZOBS), OBSOLETE, "Obsolete frame"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/frametype.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,42 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: frametype.h,v 1.7 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_FRAMETYPE_H
+# define LIBID3TAG_FRAMETYPE_H
+
+struct id3_frametype {
+  char const *id;
+  unsigned int nfields;
+  enum id3_field_type const *fields;
+  int defaultflags;
+  char const *description;
+};
+
+extern struct id3_frametype const id3_frametype_text;
+extern struct id3_frametype const id3_frametype_url;
+extern struct id3_frametype const id3_frametype_experimental;
+extern struct id3_frametype const id3_frametype_unknown;
+extern struct id3_frametype const id3_frametype_obsolete;
+
+struct id3_frametype const *id3_frametype_lookup(register char const *,
+						 register unsigned int);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/genre.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,151 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: genre.c,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include "id3tag.h"
+# include "ucs4.h"
+
+/* genres are stored in ucs4 format */
+# include "genre.dat"
+
+# define NGENRES  (sizeof(genre_table) / sizeof(genre_table[0]))
+
+/*
+ * NAME:	genre->index()
+ * DESCRIPTION:	return an ID3v1 genre string indexed by number
+ */
+id3_ucs4_t const *id3_genre_index(unsigned int index)
+{
+  return (index < NGENRES) ? genre_table[index] : 0;
+}
+
+/*
+ * NAME:	genre->name()
+ * DESCRIPTION:	translate an ID3v2 genre number/keyword to its full name
+ */
+id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *string)
+{
+  id3_ucs4_t *ptr;
+  static id3_ucs4_t const genre_remix[] = { 'R', 'e', 'm', 'i', 'x', 0 };
+  static id3_ucs4_t const genre_cover[] = { 'C', 'o', 'v', 'e', 'r', 0 };
+  unsigned long number;
+
+  if (string == 0 || *string == 0)
+    return id3_ucs4_empty;
+
+  if (string[0] == 'R' && string[1] == 'X' && string[2] == 0)
+    return genre_remix;
+  if (string[0] == 'C' && string[1] == 'R' && string[2] == 0)
+    return genre_cover;
+
+  for (ptr = string; *ptr; ++ptr) {
+    if (*ptr < '0' || *ptr > '9')
+      return string;
+  }
+
+  number = id3_ucs4_getnumber(string);
+
+  return (number < NGENRES) ? genre_table[number] : string;
+}
+
+/*
+ * NAME:	translate()
+ * DESCRIPTION:	return a canonicalized character for testing genre equivalence
+ */
+static
+id3_ucs4_t translate(id3_ucs4_t ch)
+{
+  if (ch) {
+    if (ch >= 'A' && ch <= 'Z')
+      ch += 'a' - 'A';
+
+    if (ch < 'a' || ch > 'z')
+      ch = ID3_UCS4_REPLACEMENTCHAR;
+  }
+
+  return ch;
+}
+
+/*
+ * NAME:	compare()
+ * DESCRIPTION:	test two ucs4 genre strings for equivalence
+ */
+static
+int compare(id3_ucs4_t const *str1, id3_ucs4_t const *str2)
+{
+  id3_ucs4_t c1, c2;
+
+  if (str1 == str2)
+    return 1;
+
+  do {
+    do
+      c1 = translate(*str1++);
+    while (c1 == ID3_UCS4_REPLACEMENTCHAR);
+
+    do
+      c2 = translate(*str2++);
+    while (c2 == ID3_UCS4_REPLACEMENTCHAR);
+  }
+  while (c1 && c1 == c2);
+
+  return c1 == c2;
+}
+
+/*
+ * NAME:	genre->number()
+ * DESCRIPTION:	translate an ID3v2 genre name/number to its ID3v1 index number
+ */
+int id3_genre_number(id3_ucs4_t const *string)
+{
+  id3_ucs4_t const *ptr;
+  int i;
+
+  if (string == 0 || *string == 0)
+    return -1;
+
+  for (ptr = string; *ptr; ++ptr) {
+    if (*ptr < '0' || *ptr > '9')
+      break;
+  }
+
+  if (*ptr == 0) {
+    unsigned long number;
+
+    number = id3_ucs4_getnumber(string);
+
+    return (number <= 0xff) ? number : -1;
+  }
+
+  for (i = 0; i < NGENRES; ++i) {
+    if (compare(string, genre_table[i]))
+      return i;
+  }
+
+  /* no equivalent */
+
+  return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/genre.dat	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,480 @@
+/* Automatically generated from genre.dat.in */
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * Id: genre.dat.in,v 1.7 2004/01/23 09:41:32 rob Exp 
+ */
+
+/*
+ * These are the ID3 genre names, taken as a combination of names from ID3v1
+ * (listed in Appendix A of the ID3 tag version 2.4.0 informal standard) and
+ * the extensions made by Winamp as of version 2.80.
+ */
+
+/* ID3v1 names (0-79) */
+
+static id3_ucs4_t const genre_BLUES[] =
+  { 'B', 'l', 'u', 'e', 's', 0 };
+static id3_ucs4_t const genre_CLASSIC_ROCK[] =
+  { 'C', 'l', 'a', 's', 's', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_COUNTRY[] =
+  { 'C', 'o', 'u', 'n', 't', 'r', 'y', 0 };
+static id3_ucs4_t const genre_DANCE[] =
+  { 'D', 'a', 'n', 'c', 'e', 0 };
+static id3_ucs4_t const genre_DISCO[] =
+  { 'D', 'i', 's', 'c', 'o', 0 };
+static id3_ucs4_t const genre_FUNK[] =
+  { 'F', 'u', 'n', 'k', 0 };
+static id3_ucs4_t const genre_GRUNGE[] =
+  { 'G', 'r', 'u', 'n', 'g', 'e', 0 };
+static id3_ucs4_t const genre_HIP_HOP[] =
+  { 'H', 'i', 'p', '-', 'H', 'o', 'p', 0 };
+static id3_ucs4_t const genre_JAZZ[] =
+  { 'J', 'a', 'z', 'z', 0 };
+static id3_ucs4_t const genre_METAL[] =
+  { 'M', 'e', 't', 'a', 'l', 0 };
+static id3_ucs4_t const genre_NEW_AGE[] =
+  { 'N', 'e', 'w', ' ', 'A', 'g', 'e', 0 };
+static id3_ucs4_t const genre_OLDIES[] =
+  { 'O', 'l', 'd', 'i', 'e', 's', 0 };
+static id3_ucs4_t const genre_OTHER[] =
+  { 'O', 't', 'h', 'e', 'r', 0 };
+static id3_ucs4_t const genre_POP[] =
+  { 'P', 'o', 'p', 0 };
+static id3_ucs4_t const genre_R_B[] =
+  { 'R', '&', 'B', 0 };
+static id3_ucs4_t const genre_RAP[] =
+  { 'R', 'a', 'p', 0 };
+static id3_ucs4_t const genre_REGGAE[] =
+  { 'R', 'e', 'g', 'g', 'a', 'e', 0 };
+static id3_ucs4_t const genre_ROCK[] =
+  { 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_TECHNO[] =
+  { 'T', 'e', 'c', 'h', 'n', 'o', 0 };
+static id3_ucs4_t const genre_INDUSTRIAL[] =
+  { 'I', 'n', 'd', 'u', 's', 't', 'r', 'i', 'a', 'l', 0 };
+static id3_ucs4_t const genre_ALTERNATIVE[] =
+  { 'A', 'l', 't', 'e', 'r', 'n', 'a', 't', 'i', 'v', 'e', 0 };
+static id3_ucs4_t const genre_SKA[] =
+  { 'S', 'k', 'a', 0 };
+static id3_ucs4_t const genre_DEATH_METAL[] =
+  { 'D', 'e', 'a', 't', 'h', ' ', 'M', 'e', 't', 'a', 'l', 0 };
+static id3_ucs4_t const genre_PRANKS[] =
+  { 'P', 'r', 'a', 'n', 'k', 's', 0 };
+static id3_ucs4_t const genre_SOUNDTRACK[] =
+  { 'S', 'o', 'u', 'n', 'd', 't', 'r', 'a', 'c', 'k', 0 };
+static id3_ucs4_t const genre_EURO_TECHNO[] =
+  { 'E', 'u', 'r', 'o', '-', 'T', 'e', 'c', 'h', 'n', 'o', 0 };
+static id3_ucs4_t const genre_AMBIENT[] =
+  { 'A', 'm', 'b', 'i', 'e', 'n', 't', 0 };
+static id3_ucs4_t const genre_TRIP_HOP[] =
+  { 'T', 'r', 'i', 'p', '-', 'H', 'o', 'p', 0 };
+static id3_ucs4_t const genre_VOCAL[] =
+  { 'V', 'o', 'c', 'a', 'l', 0 };
+static id3_ucs4_t const genre_JAZZ_FUNK[] =
+  { 'J', 'a', 'z', 'z', '+', 'F', 'u', 'n', 'k', 0 };
+static id3_ucs4_t const genre_FUSION[] =
+  { 'F', 'u', 's', 'i', 'o', 'n', 0 };
+static id3_ucs4_t const genre_TRANCE[] =
+  { 'T', 'r', 'a', 'n', 'c', 'e', 0 };
+static id3_ucs4_t const genre_CLASSICAL[] =
+  { 'C', 'l', 'a', 's', 's', 'i', 'c', 'a', 'l', 0 };
+static id3_ucs4_t const genre_INSTRUMENTAL[] =
+  { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', 0 };
+static id3_ucs4_t const genre_ACID[] =
+  { 'A', 'c', 'i', 'd', 0 };
+static id3_ucs4_t const genre_HOUSE[] =
+  { 'H', 'o', 'u', 's', 'e', 0 };
+static id3_ucs4_t const genre_GAME[] =
+  { 'G', 'a', 'm', 'e', 0 };
+static id3_ucs4_t const genre_SOUND_CLIP[] =
+  { 'S', 'o', 'u', 'n', 'd', ' ', 'C', 'l', 'i', 'p', 0 };
+static id3_ucs4_t const genre_GOSPEL[] =
+  { 'G', 'o', 's', 'p', 'e', 'l', 0 };
+static id3_ucs4_t const genre_NOISE[] =
+  { 'N', 'o', 'i', 's', 'e', 0 };
+static id3_ucs4_t const genre_ALTERNROCK[] =
+  { 'A', 'l', 't', 'e', 'r', 'n', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_BASS[] =
+  { 'B', 'a', 's', 's', 0 };
+static id3_ucs4_t const genre_SOUL[] =
+  { 'S', 'o', 'u', 'l', 0 };
+static id3_ucs4_t const genre_PUNK[] =
+  { 'P', 'u', 'n', 'k', 0 };
+static id3_ucs4_t const genre_SPACE[] =
+  { 'S', 'p', 'a', 'c', 'e', 0 };
+static id3_ucs4_t const genre_MEDITATIVE[] =
+  { 'M', 'e', 'd', 'i', 't', 'a', 't', 'i', 'v', 'e', 0 };
+static id3_ucs4_t const genre_INSTRUMENTAL_POP[] =
+  { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', ' ', 'P', 'o', 'p', 0 };
+static id3_ucs4_t const genre_INSTRUMENTAL_ROCK[] =
+  { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_ETHNIC[] =
+  { 'E', 't', 'h', 'n', 'i', 'c', 0 };
+static id3_ucs4_t const genre_GOTHIC[] =
+  { 'G', 'o', 't', 'h', 'i', 'c', 0 };
+static id3_ucs4_t const genre_DARKWAVE[] =
+  { 'D', 'a', 'r', 'k', 'w', 'a', 'v', 'e', 0 };
+static id3_ucs4_t const genre_TECHNO_INDUSTRIAL[] =
+  { 'T', 'e', 'c', 'h', 'n', 'o', '-', 'I', 'n', 'd', 'u', 's', 't', 'r', 'i', 'a', 'l', 0 };
+static id3_ucs4_t const genre_ELECTRONIC[] =
+  { 'E', 'l', 'e', 'c', 't', 'r', 'o', 'n', 'i', 'c', 0 };
+static id3_ucs4_t const genre_POP_FOLK[] =
+  { 'P', 'o', 'p', '-', 'F', 'o', 'l', 'k', 0 };
+static id3_ucs4_t const genre_EURODANCE[] =
+  { 'E', 'u', 'r', 'o', 'd', 'a', 'n', 'c', 'e', 0 };
+static id3_ucs4_t const genre_DREAM[] =
+  { 'D', 'r', 'e', 'a', 'm', 0 };
+static id3_ucs4_t const genre_SOUTHERN_ROCK[] =
+  { 'S', 'o', 'u', 't', 'h', 'e', 'r', 'n', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_COMEDY[] =
+  { 'C', 'o', 'm', 'e', 'd', 'y', 0 };
+static id3_ucs4_t const genre_CULT[] =
+  { 'C', 'u', 'l', 't', 0 };
+static id3_ucs4_t const genre_GANGSTA[] =
+  { 'G', 'a', 'n', 'g', 's', 't', 'a', 0 };
+static id3_ucs4_t const genre_TOP_40[] =
+  { 'T', 'o', 'p', ' ', '4', '0', 0 };
+static id3_ucs4_t const genre_CHRISTIAN_RAP[] =
+  { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'R', 'a', 'p', 0 };
+static id3_ucs4_t const genre_POP_FUNK[] =
+  { 'P', 'o', 'p', '/', 'F', 'u', 'n', 'k', 0 };
+static id3_ucs4_t const genre_JUNGLE[] =
+  { 'J', 'u', 'n', 'g', 'l', 'e', 0 };
+static id3_ucs4_t const genre_NATIVE_AMERICAN[] =
+  { 'N', 'a', 't', 'i', 'v', 'e', ' ', 'A', 'm', 'e', 'r', 'i', 'c', 'a', 'n', 0 };
+static id3_ucs4_t const genre_CABARET[] =
+  { 'C', 'a', 'b', 'a', 'r', 'e', 't', 0 };
+static id3_ucs4_t const genre_NEW_WAVE[] =
+  { 'N', 'e', 'w', ' ', 'W', 'a', 'v', 'e', 0 };
+static id3_ucs4_t const genre_PSYCHEDELIC[] =
+  { 'P', 's', 'y', 'c', 'h', 'e', 'd', 'e', 'l', 'i', 'c', 0 };
+static id3_ucs4_t const genre_RAVE[] =
+  { 'R', 'a', 'v', 'e', 0 };
+static id3_ucs4_t const genre_SHOWTUNES[] =
+  { 'S', 'h', 'o', 'w', 't', 'u', 'n', 'e', 's', 0 };
+static id3_ucs4_t const genre_TRAILER[] =
+  { 'T', 'r', 'a', 'i', 'l', 'e', 'r', 0 };
+static id3_ucs4_t const genre_LO_FI[] =
+  { 'L', 'o', '-', 'F', 'i', 0 };
+static id3_ucs4_t const genre_TRIBAL[] =
+  { 'T', 'r', 'i', 'b', 'a', 'l', 0 };
+static id3_ucs4_t const genre_ACID_PUNK[] =
+  { 'A', 'c', 'i', 'd', ' ', 'P', 'u', 'n', 'k', 0 };
+static id3_ucs4_t const genre_ACID_JAZZ[] =
+  { 'A', 'c', 'i', 'd', ' ', 'J', 'a', 'z', 'z', 0 };
+static id3_ucs4_t const genre_POLKA[] =
+  { 'P', 'o', 'l', 'k', 'a', 0 };
+static id3_ucs4_t const genre_RETRO[] =
+  { 'R', 'e', 't', 'r', 'o', 0 };
+static id3_ucs4_t const genre_MUSICAL[] =
+  { 'M', 'u', 's', 'i', 'c', 'a', 'l', 0 };
+static id3_ucs4_t const genre_ROCK___ROLL[] =
+  { 'R', 'o', 'c', 'k', ' ', '&', ' ', 'R', 'o', 'l', 'l', 0 };
+static id3_ucs4_t const genre_HARD_ROCK[] =
+  { 'H', 'a', 'r', 'd', ' ', 'R', 'o', 'c', 'k', 0 };
+
+/* Winamp extensions (80-147) */
+
+static id3_ucs4_t const genre_FOLK[] =
+  { 'F', 'o', 'l', 'k', 0 };
+static id3_ucs4_t const genre_FOLK_ROCK[] =
+  { 'F', 'o', 'l', 'k', '/', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_NATIONAL_FOLK[] =
+  { 'N', 'a', 't', 'i', 'o', 'n', 'a', 'l', ' ', 'F', 'o', 'l', 'k', 0 };
+static id3_ucs4_t const genre_SWING[] =
+  { 'S', 'w', 'i', 'n', 'g', 0 };
+static id3_ucs4_t const genre_FAST_FUSION[] =
+  { 'F', 'a', 's', 't', '-', 'F', 'u', 's', 'i', 'o', 'n', 0 };
+static id3_ucs4_t const genre_BEBOB[] =
+  { 'B', 'e', 'b', 'o', 'b', 0 };
+static id3_ucs4_t const genre_LATIN[] =
+  { 'L', 'a', 't', 'i', 'n', 0 };
+static id3_ucs4_t const genre_REVIVAL[] =
+  { 'R', 'e', 'v', 'i', 'v', 'a', 'l', 0 };
+static id3_ucs4_t const genre_CELTIC[] =
+  { 'C', 'e', 'l', 't', 'i', 'c', 0 };
+static id3_ucs4_t const genre_BLUEGRASS[] =
+  { 'B', 'l', 'u', 'e', 'g', 'r', 'a', 's', 's', 0 };
+static id3_ucs4_t const genre_AVANTGARDE[] =
+  { 'A', 'v', 'a', 'n', 't', 'g', 'a', 'r', 'd', 'e', 0 };
+static id3_ucs4_t const genre_GOTHIC_ROCK[] =
+  { 'G', 'o', 't', 'h', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_PROGRESSIVE_ROCK[] =
+  { 'P', 'r', 'o', 'g', 'r', 'e', 's', 's', 'i', 'v', 'e', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_PSYCHEDELIC_ROCK[] =
+  { 'P', 's', 'y', 'c', 'h', 'e', 'd', 'e', 'l', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_SYMPHONIC_ROCK[] =
+  { 'S', 'y', 'm', 'p', 'h', 'o', 'n', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_SLOW_ROCK[] =
+  { 'S', 'l', 'o', 'w', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_BIG_BAND[] =
+  { 'B', 'i', 'g', ' ', 'B', 'a', 'n', 'd', 0 };
+static id3_ucs4_t const genre_CHORUS[] =
+  { 'C', 'h', 'o', 'r', 'u', 's', 0 };
+static id3_ucs4_t const genre_EASY_LISTENING[] =
+  { 'E', 'a', 's', 'y', ' ', 'L', 'i', 's', 't', 'e', 'n', 'i', 'n', 'g', 0 };
+static id3_ucs4_t const genre_ACOUSTIC[] =
+  { 'A', 'c', 'o', 'u', 's', 't', 'i', 'c', 0 };
+static id3_ucs4_t const genre_HUMOUR[] =
+  { 'H', 'u', 'm', 'o', 'u', 'r', 0 };
+static id3_ucs4_t const genre_SPEECH[] =
+  { 'S', 'p', 'e', 'e', 'c', 'h', 0 };
+static id3_ucs4_t const genre_CHANSON[] =
+  { 'C', 'h', 'a', 'n', 's', 'o', 'n', 0 };
+static id3_ucs4_t const genre_OPERA[] =
+  { 'O', 'p', 'e', 'r', 'a', 0 };
+static id3_ucs4_t const genre_CHAMBER_MUSIC[] =
+  { 'C', 'h', 'a', 'm', 'b', 'e', 'r', ' ', 'M', 'u', 's', 'i', 'c', 0 };
+static id3_ucs4_t const genre_SONATA[] =
+  { 'S', 'o', 'n', 'a', 't', 'a', 0 };
+static id3_ucs4_t const genre_SYMPHONY[] =
+  { 'S', 'y', 'm', 'p', 'h', 'o', 'n', 'y', 0 };
+static id3_ucs4_t const genre_BOOTY_BASS[] =
+  { 'B', 'o', 'o', 't', 'y', ' ', 'B', 'a', 's', 's', 0 };
+static id3_ucs4_t const genre_PRIMUS[] =
+  { 'P', 'r', 'i', 'm', 'u', 's', 0 };
+static id3_ucs4_t const genre_PORN_GROOVE[] =
+  { 'P', 'o', 'r', 'n', ' ', 'G', 'r', 'o', 'o', 'v', 'e', 0 };
+static id3_ucs4_t const genre_SATIRE[] =
+  { 'S', 'a', 't', 'i', 'r', 'e', 0 };
+static id3_ucs4_t const genre_SLOW_JAM[] =
+  { 'S', 'l', 'o', 'w', ' ', 'J', 'a', 'm', 0 };
+static id3_ucs4_t const genre_CLUB[] =
+  { 'C', 'l', 'u', 'b', 0 };
+static id3_ucs4_t const genre_TANGO[] =
+  { 'T', 'a', 'n', 'g', 'o', 0 };
+static id3_ucs4_t const genre_SAMBA[] =
+  { 'S', 'a', 'm', 'b', 'a', 0 };
+static id3_ucs4_t const genre_FOLKLORE[] =
+  { 'F', 'o', 'l', 'k', 'l', 'o', 'r', 'e', 0 };
+static id3_ucs4_t const genre_BALLAD[] =
+  { 'B', 'a', 'l', 'l', 'a', 'd', 0 };
+static id3_ucs4_t const genre_POWER_BALLAD[] =
+  { 'P', 'o', 'w', 'e', 'r', ' ', 'B', 'a', 'l', 'l', 'a', 'd', 0 };
+static id3_ucs4_t const genre_RHYTHMIC_SOUL[] =
+  { 'R', 'h', 'y', 't', 'h', 'm', 'i', 'c', ' ', 'S', 'o', 'u', 'l', 0 };
+static id3_ucs4_t const genre_FREESTYLE[] =
+  { 'F', 'r', 'e', 'e', 's', 't', 'y', 'l', 'e', 0 };
+static id3_ucs4_t const genre_DUET[] =
+  { 'D', 'u', 'e', 't', 0 };
+static id3_ucs4_t const genre_PUNK_ROCK[] =
+  { 'P', 'u', 'n', 'k', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_DRUM_SOLO[] =
+  { 'D', 'r', 'u', 'm', ' ', 'S', 'o', 'l', 'o', 0 };
+static id3_ucs4_t const genre_A_CAPPELLA[] =
+  { 'A', ' ', 'C', 'a', 'p', 'p', 'e', 'l', 'l', 'a', 0 };
+static id3_ucs4_t const genre_EURO_HOUSE[] =
+  { 'E', 'u', 'r', 'o', '-', 'H', 'o', 'u', 's', 'e', 0 };
+static id3_ucs4_t const genre_DANCE_HALL[] =
+  { 'D', 'a', 'n', 'c', 'e', ' ', 'H', 'a', 'l', 'l', 0 };
+static id3_ucs4_t const genre_GOA[] =
+  { 'G', 'o', 'a', 0 };
+static id3_ucs4_t const genre_DRUM___BASS[] =
+  { 'D', 'r', 'u', 'm', ' ', '&', ' ', 'B', 'a', 's', 's', 0 };
+static id3_ucs4_t const genre_CLUB_HOUSE[] =
+  { 'C', 'l', 'u', 'b', '-', 'H', 'o', 'u', 's', 'e', 0 };
+static id3_ucs4_t const genre_HARDCORE[] =
+  { 'H', 'a', 'r', 'd', 'c', 'o', 'r', 'e', 0 };
+static id3_ucs4_t const genre_TERROR[] =
+  { 'T', 'e', 'r', 'r', 'o', 'r', 0 };
+static id3_ucs4_t const genre_INDIE[] =
+  { 'I', 'n', 'd', 'i', 'e', 0 };
+static id3_ucs4_t const genre_BRITPOP[] =
+  { 'B', 'r', 'i', 't', 'P', 'o', 'p', 0 };
+static id3_ucs4_t const genre_NEGERPUNK[] =
+  { 'N', 'e', 'g', 'e', 'r', 'p', 'u', 'n', 'k', 0 };
+static id3_ucs4_t const genre_POLSK_PUNK[] =
+  { 'P', 'o', 'l', 's', 'k', ' ', 'P', 'u', 'n', 'k', 0 };
+static id3_ucs4_t const genre_BEAT[] =
+  { 'B', 'e', 'a', 't', 0 };
+static id3_ucs4_t const genre_CHRISTIAN_GANGSTA_RAP[] =
+  { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'G', 'a', 'n', 'g', 's', 't', 'a', ' ', 'R', 'a', 'p', 0 };
+static id3_ucs4_t const genre_HEAVY_METAL[] =
+  { 'H', 'e', 'a', 'v', 'y', ' ', 'M', 'e', 't', 'a', 'l', 0 };
+static id3_ucs4_t const genre_BLACK_METAL[] =
+  { 'B', 'l', 'a', 'c', 'k', ' ', 'M', 'e', 't', 'a', 'l', 0 };
+static id3_ucs4_t const genre_CROSSOVER[] =
+  { 'C', 'r', 'o', 's', 's', 'o', 'v', 'e', 'r', 0 };
+static id3_ucs4_t const genre_CONTEMPORARY_CHRISTIAN[] =
+  { 'C', 'o', 'n', 't', 'e', 'm', 'p', 'o', 'r', 'a', 'r', 'y', ' ', 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', 0 };
+static id3_ucs4_t const genre_CHRISTIAN_ROCK[] =
+  { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'R', 'o', 'c', 'k', 0 };
+static id3_ucs4_t const genre_MERENGUE[] =
+  { 'M', 'e', 'r', 'e', 'n', 'g', 'u', 'e', 0 };
+static id3_ucs4_t const genre_SALSA[] =
+  { 'S', 'a', 'l', 's', 'a', 0 };
+static id3_ucs4_t const genre_THRASH_METAL[] =
+  { 'T', 'h', 'r', 'a', 's', 'h', ' ', 'M', 'e', 't', 'a', 'l', 0 };
+static id3_ucs4_t const genre_ANIME[] =
+  { 'A', 'n', 'i', 'm', 'e', 0 };
+static id3_ucs4_t const genre_JPOP[] =
+  { 'J', 'P', 'o', 'p', 0 };
+static id3_ucs4_t const genre_SYNTHPOP[] =
+  { 'S', 'y', 'n', 't', 'h', 'p', 'o', 'p', 0 };
+
+static id3_ucs4_t const *const genre_table[] = {
+  genre_BLUES,
+  genre_CLASSIC_ROCK,
+  genre_COUNTRY,
+  genre_DANCE,
+  genre_DISCO,
+  genre_FUNK,
+  genre_GRUNGE,
+  genre_HIP_HOP,
+  genre_JAZZ,
+  genre_METAL,
+  genre_NEW_AGE,
+  genre_OLDIES,
+  genre_OTHER,
+  genre_POP,
+  genre_R_B,
+  genre_RAP,
+  genre_REGGAE,
+  genre_ROCK,
+  genre_TECHNO,
+  genre_INDUSTRIAL,
+  genre_ALTERNATIVE,
+  genre_SKA,
+  genre_DEATH_METAL,
+  genre_PRANKS,
+  genre_SOUNDTRACK,
+  genre_EURO_TECHNO,
+  genre_AMBIENT,
+  genre_TRIP_HOP,
+  genre_VOCAL,
+  genre_JAZZ_FUNK,
+  genre_FUSION,
+  genre_TRANCE,
+  genre_CLASSICAL,
+  genre_INSTRUMENTAL,
+  genre_ACID,
+  genre_HOUSE,
+  genre_GAME,
+  genre_SOUND_CLIP,
+  genre_GOSPEL,
+  genre_NOISE,
+  genre_ALTERNROCK,
+  genre_BASS,
+  genre_SOUL,
+  genre_PUNK,
+  genre_SPACE,
+  genre_MEDITATIVE,
+  genre_INSTRUMENTAL_POP,
+  genre_INSTRUMENTAL_ROCK,
+  genre_ETHNIC,
+  genre_GOTHIC,
+  genre_DARKWAVE,
+  genre_TECHNO_INDUSTRIAL,
+  genre_ELECTRONIC,
+  genre_POP_FOLK,
+  genre_EURODANCE,
+  genre_DREAM,
+  genre_SOUTHERN_ROCK,
+  genre_COMEDY,
+  genre_CULT,
+  genre_GANGSTA,
+  genre_TOP_40,
+  genre_CHRISTIAN_RAP,
+  genre_POP_FUNK,
+  genre_JUNGLE,
+  genre_NATIVE_AMERICAN,
+  genre_CABARET,
+  genre_NEW_WAVE,
+  genre_PSYCHEDELIC,
+  genre_RAVE,
+  genre_SHOWTUNES,
+  genre_TRAILER,
+  genre_LO_FI,
+  genre_TRIBAL,
+  genre_ACID_PUNK,
+  genre_ACID_JAZZ,
+  genre_POLKA,
+  genre_RETRO,
+  genre_MUSICAL,
+  genre_ROCK___ROLL,
+  genre_HARD_ROCK,
+  genre_FOLK,
+  genre_FOLK_ROCK,
+  genre_NATIONAL_FOLK,
+  genre_SWING,
+  genre_FAST_FUSION,
+  genre_BEBOB,
+  genre_LATIN,
+  genre_REVIVAL,
+  genre_CELTIC,
+  genre_BLUEGRASS,
+  genre_AVANTGARDE,
+  genre_GOTHIC_ROCK,
+  genre_PROGRESSIVE_ROCK,
+  genre_PSYCHEDELIC_ROCK,
+  genre_SYMPHONIC_ROCK,
+  genre_SLOW_ROCK,
+  genre_BIG_BAND,
+  genre_CHORUS,
+  genre_EASY_LISTENING,
+  genre_ACOUSTIC,
+  genre_HUMOUR,
+  genre_SPEECH,
+  genre_CHANSON,
+  genre_OPERA,
+  genre_CHAMBER_MUSIC,
+  genre_SONATA,
+  genre_SYMPHONY,
+  genre_BOOTY_BASS,
+  genre_PRIMUS,
+  genre_PORN_GROOVE,
+  genre_SATIRE,
+  genre_SLOW_JAM,
+  genre_CLUB,
+  genre_TANGO,
+  genre_SAMBA,
+  genre_FOLKLORE,
+  genre_BALLAD,
+  genre_POWER_BALLAD,
+  genre_RHYTHMIC_SOUL,
+  genre_FREESTYLE,
+  genre_DUET,
+  genre_PUNK_ROCK,
+  genre_DRUM_SOLO,
+  genre_A_CAPPELLA,
+  genre_EURO_HOUSE,
+  genre_DANCE_HALL,
+  genre_GOA,
+  genre_DRUM___BASS,
+  genre_CLUB_HOUSE,
+  genre_HARDCORE,
+  genre_TERROR,
+  genre_INDIE,
+  genre_BRITPOP,
+  genre_NEGERPUNK,
+  genre_POLSK_PUNK,
+  genre_BEAT,
+  genre_CHRISTIAN_GANGSTA_RAP,
+  genre_HEAVY_METAL,
+  genre_BLACK_METAL,
+  genre_CROSSOVER,
+  genre_CONTEMPORARY_CHRISTIAN,
+  genre_CHRISTIAN_ROCK,
+  genre_MERENGUE,
+  genre_SALSA,
+  genre_THRASH_METAL,
+  genre_ANIME,
+  genre_JPOP,
+  genre_SYNTHPOP
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/genre.dat.in	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,180 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: genre.dat.in,v 1.7 2004/01/23 09:41:32 rob Exp $
+ */
+
+/*
+ * These are the ID3 genre names, taken as a combination of names from ID3v1
+ * (listed in Appendix A of the ID3 tag version 2.4.0 informal standard) and
+ * the extensions made by Winamp as of version 2.80.
+ */
+
+/* ID3v1 names (0-79) */
+
+Blues
+Classic Rock
+Country
+Dance
+Disco
+Funk
+Grunge
+Hip-Hop
+Jazz
+Metal
+New Age
+Oldies
+Other
+Pop
+R&B
+Rap
+Reggae
+Rock
+Techno
+Industrial
+Alternative
+Ska
+Death Metal
+Pranks
+Soundtrack
+Euro-Techno
+Ambient
+Trip-Hop
+Vocal
+Jazz+Funk
+Fusion
+Trance
+Classical
+Instrumental
+Acid
+House
+Game
+Sound Clip
+Gospel
+Noise
+AlternRock
+Bass
+Soul
+Punk
+Space
+Meditative
+Instrumental Pop
+Instrumental Rock
+Ethnic
+Gothic
+Darkwave
+Techno-Industrial
+Electronic
+Pop-Folk
+Eurodance
+Dream
+Southern Rock
+Comedy
+Cult
+Gangsta
+Top 40
+Christian Rap
+Pop/Funk
+Jungle
+Native American
+Cabaret
+New Wave
+Psychedelic
+Rave
+Showtunes
+Trailer
+Lo-Fi
+Tribal
+Acid Punk
+Acid Jazz
+Polka
+Retro
+Musical
+Rock & Roll
+Hard Rock
+
+/* Winamp extensions (80-147) */
+
+Folk
+Folk/Rock
+National Folk
+Swing
+Fast-Fusion
+Bebob
+Latin
+Revival
+Celtic
+Bluegrass
+Avantgarde
+Gothic Rock
+Progressive Rock
+Psychedelic Rock
+Symphonic Rock
+Slow Rock
+Big Band
+Chorus
+Easy Listening
+Acoustic
+Humour
+Speech
+Chanson
+Opera
+Chamber Music
+Sonata
+Symphony
+Booty Bass
+Primus
+Porn Groove
+Satire
+Slow Jam
+Club
+Tango
+Samba
+Folklore
+Ballad
+Power Ballad
+Rhythmic Soul
+Freestyle
+Duet
+Punk Rock
+Drum Solo
+A Cappella
+Euro-House
+Dance Hall
+Goa
+Drum & Bass
+Club-House
+Hardcore
+Terror
+Indie
+BritPop
+Negerpunk
+Polsk Punk
+Beat
+Christian Gangsta Rap
+Heavy Metal
+Black Metal
+Crossover
+Contemporary Christian
+Christian Rock
+Merengue
+Salsa
+Thrash Metal
+Anime
+JPop
+Synthpop
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/genre.dat.sed	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,54 @@
+#
+# libid3tag - ID3 tag manipulation library
+# Copyright (C) 2000-2004 Underbit Technologies, Inc.
+#
+# 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
+#
+# $Id: genre.dat.sed,v 1.10 2004/01/23 09:41:32 rob Exp $
+#
+
+1i\
+/* Automatically generated from genre.dat.in */
+
+# generate an array from a string
+/^[A-Za-z]/{
+H
+y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
+s/[^A-Z0-9]/_/g
+s/.*/static id3_ucs4_t const genre_&[] =/p
+g
+s/.*\n//
+s/./'&', /g
+s/.*/  { &0 };/
+}
+
+# write the final table of arrays
+${
+p
+i\
+\
+static id3_ucs4_t const *const genre_table[] = {
+g
+s/^\(\n\)\(.*\)$/\2\1/
+y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
+s/[^A-Z0-9\n]/_/g
+s/\([^\n]*\)\(\n\)/  genre_\1,\2/g
+s/,\n$//
+a\
+};
+}
+
+# print the pattern space (assumes -n)
+p
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/genre.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,27 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: genre.h,v 1.6 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_GENRE_H
+# define LIBID3TAG_GENRE_H
+
+# define ID3_GENRE_OTHER  12
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/global.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,53 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: global.h,v 1.9 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_GLOBAL_H
+# define LIBID3TAG_GLOBAL_H
+
+/* conditional debugging */
+
+# if defined(DEBUG) && defined(NDEBUG)
+#  error "cannot define both DEBUG and NDEBUG"
+# endif
+
+# if defined(DEBUG)
+#  include <stdio.h>
+#  include "debug.h"
+#  define malloc(sz)        id3_debug_malloc(sz,       __FILE__, __LINE__)
+#  define calloc(n, sz)     id3_debug_calloc(n, sz,    __FILE__, __LINE__)
+#  define realloc(ptr, sz)  id3_debug_realloc(ptr, sz, __FILE__, __LINE__)
+#  define free(ptr)         id3_debug_free(ptr,        __FILE__, __LINE__)
+#  define release(ptr)      id3_debug_release(ptr,     __FILE__, __LINE__)
+# else
+#  define release(ptr)  (ptr)
+# endif
+
+/* conditional features */
+
+# if !defined(HAVE_ASSERT_H)
+#  if defined(NDEBUG)
+#   define assert(x)	/* nothing */
+#  else
+#   define assert(x)	do { if (!(x)) abort(); } while (0)
+#  endif
+# endif
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/id3tag.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,364 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * If you would like to negotiate alternate licensing terms, you may do
+ * so by contacting: Underbit Technologies, Inc. <info@underbit.com>
+ *
+ * $Id: id3tag.h,v 1.17 2004/01/23 23:22:46 rob Exp $
+ */
+
+# ifndef LIBID3TAG_ID3TAG_H
+# define LIBID3TAG_ID3TAG_H
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# define ID3_TAG_VERSION		0x0400
+# define ID3_TAG_VERSION_MAJOR(x)	(((x) >> 8) & 0xff)
+# define ID3_TAG_VERSION_MINOR(x)	(((x) >> 0) & 0xff)
+
+typedef unsigned char id3_byte_t;
+typedef unsigned long id3_length_t;
+
+typedef unsigned long id3_ucs4_t;
+
+typedef unsigned char id3_latin1_t;
+typedef unsigned short id3_utf16_t;
+typedef signed char id3_utf8_t;
+
+struct id3_tag {
+  unsigned int refcount;
+  unsigned int version;
+  int flags;
+  int extendedflags;
+  int restrictions;
+  int options;
+  unsigned int nframes;
+  struct id3_frame **frames;
+  id3_length_t paddedsize;
+};
+
+# define ID3_TAG_QUERYSIZE	10
+
+/* ID3v1 field frames */
+
+# define ID3_FRAME_TITLE	"TIT2"
+# define ID3_FRAME_ARTIST	"TPE1"
+# define ID3_FRAME_ALBUM	"TALB"
+# define ID3_FRAME_TRACK	"TRCK"
+# define ID3_FRAME_YEAR		"TDRC"
+# define ID3_FRAME_GENRE	"TCON"
+# define ID3_FRAME_COMMENT	"COMM"
+
+/* special frames */
+
+# define ID3_FRAME_OBSOLETE	"ZOBS"	/* with apologies to the French */
+
+/* tag flags */
+
+enum {
+  ID3_TAG_FLAG_UNSYNCHRONISATION     = 0x80,
+  ID3_TAG_FLAG_EXTENDEDHEADER        = 0x40,
+  ID3_TAG_FLAG_EXPERIMENTALINDICATOR = 0x20,
+  ID3_TAG_FLAG_FOOTERPRESENT         = 0x10,
+
+  ID3_TAG_FLAG_KNOWNFLAGS            = 0xf0
+};
+
+/* tag extended flags */
+
+enum {
+  ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE   = 0x40,
+  ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT  = 0x20,
+  ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS = 0x10,
+
+  ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS      = 0x70
+};
+
+/* tag restrictions */
+
+enum {
+  ID3_TAG_RESTRICTION_TAGSIZE_MASK             = 0xc0,
+  ID3_TAG_RESTRICTION_TAGSIZE_128_FRAMES_1_MB  = 0x00,
+  ID3_TAG_RESTRICTION_TAGSIZE_64_FRAMES_128_KB = 0x40,
+  ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_40_KB  = 0x80,
+  ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_4_KB   = 0xc0
+};
+
+enum {
+  ID3_TAG_RESTRICTION_TEXTENCODING_MASK        = 0x20,
+  ID3_TAG_RESTRICTION_TEXTENCODING_NONE        = 0x00,
+  ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 = 0x20
+};
+
+enum {
+  ID3_TAG_RESTRICTION_TEXTSIZE_MASK            = 0x18,
+  ID3_TAG_RESTRICTION_TEXTSIZE_NONE            = 0x00,
+  ID3_TAG_RESTRICTION_TEXTSIZE_1024_CHARS      = 0x08,
+  ID3_TAG_RESTRICTION_TEXTSIZE_128_CHARS       = 0x10,
+  ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS        = 0x18
+};
+
+enum {
+  ID3_TAG_RESTRICTION_IMAGEENCODING_MASK       = 0x04,
+  ID3_TAG_RESTRICTION_IMAGEENCODING_NONE       = 0x00,
+  ID3_TAG_RESTRICTION_IMAGEENCODING_PNG_JPEG   = 0x04
+};
+
+enum {
+  ID3_TAG_RESTRICTION_IMAGESIZE_MASK           = 0x03,
+  ID3_TAG_RESTRICTION_IMAGESIZE_NONE           = 0x00,
+  ID3_TAG_RESTRICTION_IMAGESIZE_256_256        = 0x01,
+  ID3_TAG_RESTRICTION_IMAGESIZE_64_64          = 0x02,
+  ID3_TAG_RESTRICTION_IMAGESIZE_64_64_EXACT    = 0x03
+};
+
+/* library options */
+
+enum {
+  ID3_TAG_OPTION_UNSYNCHRONISATION = 0x0001,	/* use unsynchronisation */
+  ID3_TAG_OPTION_COMPRESSION       = 0x0002,	/* use compression */
+  ID3_TAG_OPTION_CRC               = 0x0004,	/* use CRC */
+
+  ID3_TAG_OPTION_APPENDEDTAG       = 0x0010,	/* tag will be appended */
+  ID3_TAG_OPTION_FILEALTERED       = 0x0020,	/* audio data was altered */
+
+  ID3_TAG_OPTION_ID3V1             = 0x0100	/* render ID3v1/ID3v1.1 tag */
+};
+
+struct id3_frame {
+  char id[5];
+  char const *description;
+  unsigned int refcount;
+  int flags;
+  int group_id;
+  int encryption_method;
+  id3_byte_t *encoded;
+  id3_length_t encoded_length;
+  id3_length_t decoded_length;
+  unsigned int nfields;
+  union id3_field *fields;
+};
+
+enum {
+  /* frame status flags */
+  ID3_FRAME_FLAG_TAGALTERPRESERVATION	= 0x4000,
+  ID3_FRAME_FLAG_FILEALTERPRESERVATION	= 0x2000,
+  ID3_FRAME_FLAG_READONLY		= 0x1000,
+
+  ID3_FRAME_FLAG_STATUSFLAGS            = 0xff00,
+
+  /* frame format flags */
+  ID3_FRAME_FLAG_GROUPINGIDENTITY	= 0x0040,
+  ID3_FRAME_FLAG_COMPRESSION		= 0x0008,
+  ID3_FRAME_FLAG_ENCRYPTION		= 0x0004,
+  ID3_FRAME_FLAG_UNSYNCHRONISATION	= 0x0002,
+  ID3_FRAME_FLAG_DATALENGTHINDICATOR	= 0x0001,
+
+  ID3_FRAME_FLAG_FORMATFLAGS            = 0x00ff,
+
+  ID3_FRAME_FLAG_KNOWNFLAGS             = 0x704f
+};
+
+enum id3_field_type {
+  ID3_FIELD_TYPE_TEXTENCODING,
+  ID3_FIELD_TYPE_LATIN1,
+  ID3_FIELD_TYPE_LATIN1FULL,
+  ID3_FIELD_TYPE_LATIN1LIST,
+  ID3_FIELD_TYPE_STRING,
+  ID3_FIELD_TYPE_STRINGFULL,
+  ID3_FIELD_TYPE_STRINGLIST,
+  ID3_FIELD_TYPE_LANGUAGE,
+  ID3_FIELD_TYPE_FRAMEID,
+  ID3_FIELD_TYPE_DATE,
+  ID3_FIELD_TYPE_INT8,
+  ID3_FIELD_TYPE_INT16,
+  ID3_FIELD_TYPE_INT24,
+  ID3_FIELD_TYPE_INT32,
+  ID3_FIELD_TYPE_INT32PLUS,
+  ID3_FIELD_TYPE_BINARYDATA
+};
+
+enum id3_field_textencoding {
+  ID3_FIELD_TEXTENCODING_ISO_8859_1 = 0x00,
+  ID3_FIELD_TEXTENCODING_UTF_16     = 0x01,
+  ID3_FIELD_TEXTENCODING_UTF_16BE   = 0x02,
+  ID3_FIELD_TEXTENCODING_UTF_8      = 0x03
+};
+
+union id3_field {
+  enum id3_field_type type;
+  struct {
+    enum id3_field_type type;
+    signed long value;
+  } number;
+  struct {
+    enum id3_field_type type;
+    id3_latin1_t *ptr;
+  } latin1;
+  struct {
+    enum id3_field_type type;
+    unsigned int nstrings;
+    id3_latin1_t **strings;
+  } latin1list;
+  struct {
+    enum id3_field_type type;
+    id3_ucs4_t *ptr;
+  } string;
+  struct {
+    enum id3_field_type type;
+    unsigned int nstrings;
+    id3_ucs4_t **strings;
+  } stringlist;
+  struct {
+    enum id3_field_type type;
+    char value[9];
+  } immediate;
+  struct {
+    enum id3_field_type type;
+    id3_byte_t *data;
+    id3_length_t length;
+  } binary;
+};
+
+/* file interface */
+
+enum id3_file_mode {
+  ID3_FILE_MODE_READONLY = 0,
+  ID3_FILE_MODE_READWRITE
+};
+
+struct id3_file *id3_file_open(char const *, enum id3_file_mode);
+struct id3_file *id3_file_fdopen(int, enum id3_file_mode);
+int id3_file_close(struct id3_file *);
+
+struct id3_tag *id3_file_tag(struct id3_file const *);
+
+int id3_file_update(struct id3_file *);
+
+/* tag interface */
+
+struct id3_tag *id3_tag_new(void);
+void id3_tag_delete(struct id3_tag *);
+
+unsigned int id3_tag_version(struct id3_tag const *);
+
+int id3_tag_options(struct id3_tag *, int, int);
+void id3_tag_setlength(struct id3_tag *, id3_length_t);
+
+void id3_tag_clearframes(struct id3_tag *);
+
+int id3_tag_attachframe(struct id3_tag *, struct id3_frame *);
+int id3_tag_detachframe(struct id3_tag *, struct id3_frame *);
+
+struct id3_frame *id3_tag_findframe(struct id3_tag const *,
+				    char const *, unsigned int);
+
+signed long id3_tag_query(id3_byte_t const *, id3_length_t);
+
+struct id3_tag *id3_tag_parse(id3_byte_t const *, id3_length_t);
+id3_length_t id3_tag_render(struct id3_tag const *, id3_byte_t *);
+
+/* frame interface */
+
+struct id3_frame *id3_frame_new(char const *);
+void id3_frame_delete(struct id3_frame *);
+
+union id3_field *id3_frame_field(struct id3_frame const *, unsigned int);
+
+/* field interface */
+
+enum id3_field_type id3_field_type(union id3_field const *);
+
+int id3_field_setint(union id3_field *, signed long);
+int id3_field_settextencoding(union id3_field *, enum id3_field_textencoding);
+int id3_field_setstrings(union id3_field *, unsigned int, id3_ucs4_t **);
+int id3_field_addstring(union id3_field *, id3_ucs4_t const *);
+int id3_field_setlanguage(union id3_field *, char const *);
+int id3_field_setlatin1(union id3_field *, id3_latin1_t const *);
+int id3_field_setfulllatin1(union id3_field *, id3_latin1_t const *);
+int id3_field_setstring(union id3_field *, id3_ucs4_t const *);
+int id3_field_setfullstring(union id3_field *, id3_ucs4_t const *);
+int id3_field_setframeid(union id3_field *, char const *);
+int id3_field_setbinarydata(union id3_field *,
+			    id3_byte_t const *, id3_length_t);
+
+signed long id3_field_getint(union id3_field const *);
+enum id3_field_textencoding id3_field_gettextencoding(union id3_field const *);
+id3_latin1_t const *id3_field_getlatin1(union id3_field const *);
+id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *);
+id3_ucs4_t const *id3_field_getstring(union id3_field const *);
+id3_ucs4_t const *id3_field_getfullstring(union id3_field const *);
+unsigned int id3_field_getnstrings(union id3_field const *);
+id3_ucs4_t const *id3_field_getstrings(union id3_field const *,
+				       unsigned int);
+char const *id3_field_getframeid(union id3_field const *);
+id3_byte_t const *id3_field_getbinarydata(union id3_field const *,
+					  id3_length_t *);
+
+/* genre interface */
+
+id3_ucs4_t const *id3_genre_index(unsigned int);
+id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *);
+int id3_genre_number(id3_ucs4_t const *);
+
+/* ucs4 interface */
+
+id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *);
+id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *);
+id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *);
+
+void id3_ucs4_putnumber(id3_ucs4_t *, unsigned long);
+unsigned long id3_ucs4_getnumber(id3_ucs4_t const *);
+
+/* latin1/utf16/utf8 interfaces */
+
+id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *);
+id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *);
+id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *);
+
+/* version interface */
+
+# define ID3_VERSION_MAJOR	0
+# define ID3_VERSION_MINOR	15
+# define ID3_VERSION_PATCH	1
+# define ID3_VERSION_EXTRA	" (beta)"
+
+# define ID3_VERSION_STRINGIZE(str)	#str
+# define ID3_VERSION_STRING(num)	ID3_VERSION_STRINGIZE(num)
+
+# define ID3_VERSION	ID3_VERSION_STRING(ID3_VERSION_MAJOR) "."  \
+			ID3_VERSION_STRING(ID3_VERSION_MINOR) "."  \
+			ID3_VERSION_STRING(ID3_VERSION_PATCH)  \
+			ID3_VERSION_EXTRA
+
+# define ID3_PUBLISHYEAR	"2000-2004"
+# define ID3_AUTHOR		"Underbit Technologies, Inc."
+# define ID3_EMAIL		"info@underbit.com"
+
+extern char const id3_version[];
+extern char const id3_copyright[];
+extern char const id3_author[];
+extern char const id3_build[];
+
+# ifdef __cplusplus
+}
+# endif
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/latin1.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,217 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: latin1.c,v 1.10 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+
+# include "id3tag.h"
+# include "latin1.h"
+# include "ucs4.h"
+
+/*
+ * NAME:	latin1->length()
+ * DESCRIPTION:	return the number of ucs4 chars represented by a latin1 string
+ */
+id3_length_t id3_latin1_length(id3_latin1_t const *latin1)
+{
+  id3_latin1_t const *ptr = latin1;
+
+  while (*ptr)
+    ++ptr;
+
+  return ptr - latin1;
+}
+
+/*
+ * NAME:	latin1->size()
+ * DESCRIPTION:	return the encoding size of a latin1 string
+ */
+id3_length_t id3_latin1_size(id3_latin1_t const *latin1)
+{
+  return id3_latin1_length(latin1) + 1;
+}
+
+/*
+ * NAME:	latin1->copy()
+ * DESCRIPTION:	copy a latin1 string
+ */
+void id3_latin1_copy(id3_latin1_t *dest, id3_latin1_t const *src)
+{
+  while ((*dest++ = *src++))
+    ;
+}
+
+/*
+ * NAME:	latin1->duplicate()
+ * DESCRIPTION:	duplicate a latin1 string
+ */
+id3_latin1_t *id3_latin1_duplicate(id3_latin1_t const *src)
+{
+  id3_latin1_t *latin1;
+
+  latin1 = malloc(id3_latin1_size(src) * sizeof(*latin1));
+  if (latin1)
+    id3_latin1_copy(latin1, src);
+
+  return latin1;
+}
+
+/*
+ * NAME:	latin1->ucs4duplicate()
+ * DESCRIPTION:	duplicate and decode a latin1 string into ucs4
+ */
+id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *latin1)
+{
+  id3_ucs4_t *ucs4;
+
+  ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4));
+  if (ucs4)
+    id3_latin1_decode(latin1, ucs4);
+
+  return release(ucs4);
+}
+
+/*
+ * NAME:	latin1->decodechar()
+ * DESCRIPTION:	decode a (single) latin1 char into a single ucs4 char
+ */
+id3_length_t id3_latin1_decodechar(id3_latin1_t const *latin1,
+				   id3_ucs4_t *ucs4)
+{
+  *ucs4 = *latin1;
+
+  return 1;
+}
+
+/*
+ * NAME:	latin1->encodechar()
+ * DESCRIPTION:	encode a single ucs4 char into a (single) latin1 char
+ */
+id3_length_t id3_latin1_encodechar(id3_latin1_t *latin1, id3_ucs4_t ucs4)
+{
+  *latin1 = ucs4;
+  if (ucs4 > 0x000000ffL)
+    *latin1 = ID3_UCS4_REPLACEMENTCHAR;
+
+  return 1;
+}
+
+/*
+ * NAME:	latin1->decode()
+ * DESCRIPTION:	decode a complete latin1 string into a ucs4 string
+ */
+void id3_latin1_decode(id3_latin1_t const *latin1, id3_ucs4_t *ucs4)
+{
+  do
+    latin1 += id3_latin1_decodechar(latin1, ucs4);
+  while (*ucs4++);
+}
+
+/*
+ * NAME:	latin1->encode()
+ * DESCRIPTION:	encode a complete ucs4 string into a latin1 string
+ */
+void id3_latin1_encode(id3_latin1_t *latin1, id3_ucs4_t const *ucs4)
+{
+  do
+    latin1 += id3_latin1_encodechar(latin1, *ucs4);
+  while (*ucs4++);
+}
+
+/*
+ * NAME:	latin1->put()
+ * DESCRIPTION:	serialize a single latin1 character
+ */
+id3_length_t id3_latin1_put(id3_byte_t **ptr, id3_latin1_t latin1)
+{
+  if (ptr)
+    *(*ptr)++ = latin1;
+
+  return 1;
+}
+
+/*
+ * NAME:	latin1->get()
+ * DESCRIPTION:	deserialize a single latin1 character
+ */
+id3_latin1_t id3_latin1_get(id3_byte_t const **ptr)
+{
+  return *(*ptr)++;
+}
+
+/*
+ * NAME:	latin1->serialize()
+ * DESCRIPTION:	serialize a ucs4 string using latin1 encoding
+ */
+id3_length_t id3_latin1_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4,
+				  int terminate)
+{
+  id3_length_t size = 0;
+  id3_latin1_t latin1[1], *out;
+
+  while (*ucs4) {
+    switch (id3_latin1_encodechar(out = latin1, *ucs4++)) {
+    case 1: size += id3_latin1_put(ptr, *out++);
+    case 0: break;
+    }
+  }
+
+  if (terminate)
+    size += id3_latin1_put(ptr, 0);
+
+  return size;
+}
+
+/*
+ * NAME:	latin1->deserialize()
+ * DESCRIPTION:	deserialize a ucs4 string using latin1 encoding
+ */
+id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **ptr, id3_length_t length)
+{
+  id3_byte_t const *end;
+  id3_latin1_t *latin1ptr, *latin1;
+  id3_ucs4_t *ucs4;
+
+  end = *ptr + length;
+
+  latin1 = malloc((length + 1) * sizeof(*latin1));
+  if (latin1 == 0)
+    return 0;
+
+  latin1ptr = latin1;
+  while (end - *ptr > 0 && (*latin1ptr = id3_latin1_get(ptr)))
+    ++latin1ptr;
+
+  *latin1ptr = 0;
+
+  ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4));
+  if (ucs4)
+    id3_latin1_decode(latin1, ucs4);
+
+  free(latin1);
+
+  return ucs4;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/latin1.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,45 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: latin1.h,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_LATIN1_H
+# define LIBID3TAG_LATIN1_H
+
+# include "id3tag.h"
+
+id3_length_t id3_latin1_length(id3_latin1_t const *);
+id3_length_t id3_latin1_size(id3_latin1_t const *);
+
+void id3_latin1_copy(id3_latin1_t *, id3_latin1_t const *);
+id3_latin1_t *id3_latin1_duplicate(id3_latin1_t const *);
+
+id3_length_t id3_latin1_decodechar(id3_latin1_t const *, id3_ucs4_t *);
+id3_length_t id3_latin1_encodechar(id3_latin1_t *, id3_ucs4_t);
+
+void id3_latin1_decode(id3_latin1_t const *, id3_ucs4_t *);
+void id3_latin1_encode(id3_latin1_t *, id3_ucs4_t const *);
+
+id3_length_t id3_latin1_put(id3_byte_t **, id3_latin1_t);
+id3_latin1_t id3_latin1_get(id3_byte_t const **);
+
+id3_length_t id3_latin1_serialize(id3_byte_t **, id3_ucs4_t const *, int);
+id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **, id3_length_t);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/parse.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,196 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: parse.c,v 1.9 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include <stdlib.h>
+# include <string.h>
+
+# include "id3tag.h"
+# include "parse.h"
+# include "latin1.h"
+# include "utf16.h"
+# include "utf8.h"
+
+signed long id3_parse_int(id3_byte_t const **ptr, unsigned int bytes)
+{
+  signed long value = 0;
+
+  assert(bytes >= 1 && bytes <= 4);
+
+  if (**ptr & 0x80)
+    value = ~0;
+
+  switch (bytes) {
+  case 4: value = (value << 8) | *(*ptr)++;
+  case 3: value = (value << 8) | *(*ptr)++;
+  case 2: value = (value << 8) | *(*ptr)++;
+  case 1: value = (value << 8) | *(*ptr)++;
+  }
+
+  return value;
+}
+
+unsigned long id3_parse_uint(id3_byte_t const **ptr, unsigned int bytes)
+{
+  unsigned long value = 0;
+
+  assert(bytes >= 1 && bytes <= 4);
+
+  switch (bytes) {
+  case 4: value = (value << 8) | *(*ptr)++;
+  case 3: value = (value << 8) | *(*ptr)++;
+  case 2: value = (value << 8) | *(*ptr)++;
+  case 1: value = (value << 8) | *(*ptr)++;
+  }
+
+  return value;
+}
+
+unsigned long id3_parse_syncsafe(id3_byte_t const **ptr, unsigned int bytes)
+{
+  unsigned long value = 0;
+
+  assert(bytes == 4 || bytes == 5);
+
+  switch (bytes) {
+  case 5: value = (value << 4) | (*(*ptr)++ & 0x0f);
+  case 4: value = (value << 7) | (*(*ptr)++ & 0x7f);
+          value = (value << 7) | (*(*ptr)++ & 0x7f);
+	  value = (value << 7) | (*(*ptr)++ & 0x7f);
+	  value = (value << 7) | (*(*ptr)++ & 0x7f);
+  }
+
+  return value;
+}
+
+void id3_parse_immediate(id3_byte_t const **ptr, unsigned int bytes,
+			 char *value)
+{
+  assert(value);
+  assert(bytes == 8 || bytes == 4 || bytes == 3);
+
+  switch (bytes) {
+  case 8: *value++ = *(*ptr)++;
+          *value++ = *(*ptr)++;
+	  *value++ = *(*ptr)++;
+	  *value++ = *(*ptr)++;
+  case 4: *value++ = *(*ptr)++;
+  case 3: *value++ = *(*ptr)++;
+          *value++ = *(*ptr)++;
+	  *value++ = *(*ptr)++;
+  }
+
+  *value = 0;
+}
+
+id3_latin1_t *id3_parse_latin1(id3_byte_t const **ptr, id3_length_t length,
+			       int full)
+{
+  id3_byte_t const *end;
+  int terminated = 0;
+  id3_latin1_t *latin1;
+
+  end = memchr(*ptr, 0, length);
+  if (end == 0)
+    end = *ptr + length;
+  else {
+    length = end - *ptr;
+    terminated = 1;
+  }
+
+  latin1 = malloc(length + 1);
+  if (latin1) {
+    memcpy(latin1, *ptr, length);
+    latin1[length] = 0;
+
+    if (!full) {
+      id3_latin1_t *check;
+
+      for (check = latin1; *check; ++check) {
+	if (*check == '\n')
+	  *check = ' ';
+      }
+    }
+  }
+
+  *ptr += length + terminated;
+
+  return latin1;
+}
+
+id3_ucs4_t *id3_parse_string(id3_byte_t const **ptr, id3_length_t length,
+			     enum id3_field_textencoding encoding, int full)
+{
+  id3_ucs4_t *ucs4 = 0;
+  enum id3_utf16_byteorder byteorder = ID3_UTF16_BYTEORDER_ANY;
+
+  switch (encoding) {
+  case ID3_FIELD_TEXTENCODING_ISO_8859_1:
+    ucs4 = id3_latin1_deserialize(ptr, length);
+    break;
+
+  case ID3_FIELD_TEXTENCODING_UTF_16BE:
+    byteorder = ID3_UTF16_BYTEORDER_BE;
+  case ID3_FIELD_TEXTENCODING_UTF_16:
+    ucs4 = id3_utf16_deserialize(ptr, length, byteorder);
+    break;
+
+  case ID3_FIELD_TEXTENCODING_UTF_8:
+    ucs4 = id3_utf8_deserialize(ptr, length);
+    break;
+  }
+
+  if (ucs4 && !full) {
+    id3_ucs4_t *check;
+
+    for (check = ucs4; *check; ++check) {
+      if (*check == '\n')
+	*check = ' ';
+    }
+  }
+
+  return ucs4;
+}
+
+id3_byte_t *id3_parse_binary(id3_byte_t const **ptr, id3_length_t length)
+{
+  id3_byte_t *data;
+
+  if (length == 0)
+    return malloc(1);
+
+  data = malloc(length);
+  if (data)
+    memcpy(data, *ptr, length);
+
+  *ptr += length;
+
+  return data;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/parse.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,34 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: parse.h,v 1.6 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_PARSE_H
+# define LIBID3TAG_PARSE_H
+
+signed long id3_parse_int(id3_byte_t const **, unsigned int);
+unsigned long id3_parse_uint(id3_byte_t const **, unsigned int);
+unsigned long id3_parse_syncsafe(id3_byte_t const **, unsigned int);
+void id3_parse_immediate(id3_byte_t const **, unsigned int, char *);
+id3_latin1_t *id3_parse_latin1(id3_byte_t const **, id3_length_t, int);
+id3_ucs4_t *id3_parse_string(id3_byte_t const **, id3_length_t,
+			     enum id3_field_textencoding, int);
+id3_byte_t *id3_parse_binary(id3_byte_t const **, id3_length_t);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/render.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,201 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: render.c,v 1.11 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <string.h>
+# include <stdlib.h>
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include "id3tag.h"
+# include "render.h"
+# include "ucs4.h"
+# include "latin1.h"
+# include "utf16.h"
+# include "utf8.h"
+
+id3_length_t id3_render_immediate(id3_byte_t **ptr,
+				  char const *value, unsigned int bytes)
+{
+  assert(value);
+  assert(bytes == 8 || bytes == 4 || bytes == 3);
+
+  if (ptr) {
+    switch (bytes) {
+    case 8: *(*ptr)++ = *value++;
+            *(*ptr)++ = *value++;
+	    *(*ptr)++ = *value++;
+	    *(*ptr)++ = *value++;
+    case 4: *(*ptr)++ = *value++;
+    case 3: *(*ptr)++ = *value++;
+            *(*ptr)++ = *value++;
+	    *(*ptr)++ = *value++;
+    }
+  }
+
+  return bytes;
+}
+
+id3_length_t id3_render_syncsafe(id3_byte_t **ptr,
+				 unsigned long num, unsigned int bytes)
+{
+  assert(bytes == 4 || bytes == 5);
+
+  if (ptr) {
+    switch (bytes) {
+    case 5: *(*ptr)++ = (num >> 28) & 0x0f;
+    case 4: *(*ptr)++ = (num >> 21) & 0x7f;
+            *(*ptr)++ = (num >> 14) & 0x7f;
+	    *(*ptr)++ = (num >>  7) & 0x7f;
+	    *(*ptr)++ = (num >>  0) & 0x7f;
+    }
+  }
+
+  return bytes;
+}
+
+id3_length_t id3_render_int(id3_byte_t **ptr,
+			    signed long num, unsigned int bytes)
+{
+  assert(bytes >= 1 && bytes <= 4);
+
+  if (ptr) {
+    switch (bytes) {
+    case 4: *(*ptr)++ = num >> 24;
+    case 3: *(*ptr)++ = num >> 16;
+    case 2: *(*ptr)++ = num >>  8;
+    case 1: *(*ptr)++ = num >>  0;
+    }
+  }
+
+  return bytes;
+}
+
+id3_length_t id3_render_binary(id3_byte_t **ptr,
+			       id3_byte_t const *data, id3_length_t length)
+{
+  if (data == 0)
+    return 0;
+
+  if (ptr) {
+    memcpy(*ptr, data, length);
+    *ptr += length;
+  }
+
+  return length;
+}
+
+id3_length_t id3_render_latin1(id3_byte_t **ptr,
+			       id3_latin1_t const *latin1, int terminate)
+{
+  id3_length_t size;
+
+  if (latin1 == 0)
+    latin1 = "";
+
+  size = id3_latin1_size(latin1);
+  if (!terminate)
+    --size;
+
+  if (ptr) {
+    memcpy(*ptr, latin1, size);
+    *ptr += size;
+  }
+
+  return size;
+}
+
+id3_length_t id3_render_string(id3_byte_t **ptr, id3_ucs4_t const *ucs4,
+			       enum id3_field_textencoding encoding,
+			       int terminate)
+{
+  enum id3_utf16_byteorder byteorder = ID3_UTF16_BYTEORDER_ANY;
+
+  if (ucs4 == 0)
+    ucs4 = id3_ucs4_empty;
+
+  switch (encoding) {
+  case ID3_FIELD_TEXTENCODING_ISO_8859_1:
+    return id3_latin1_serialize(ptr, ucs4, terminate);
+
+  case ID3_FIELD_TEXTENCODING_UTF_16BE:
+    byteorder = ID3_UTF16_BYTEORDER_BE;
+  case ID3_FIELD_TEXTENCODING_UTF_16:
+    return id3_utf16_serialize(ptr, ucs4, byteorder, terminate);
+
+  case ID3_FIELD_TEXTENCODING_UTF_8:
+    return id3_utf8_serialize(ptr, ucs4, terminate);
+  }
+
+  return 0;
+}
+
+id3_length_t id3_render_padding(id3_byte_t **ptr, id3_byte_t value,
+				id3_length_t length)
+{
+  if (ptr) {
+    memset(*ptr, value, length);
+    *ptr += length;
+  }
+
+  return length;
+}
+
+/*
+ * NAME:	render->paddedstring()
+ * DESCRIPTION:	render a space-padded string using latin1 encoding
+ */
+id3_length_t id3_render_paddedstring(id3_byte_t **ptr, id3_ucs4_t const *ucs4,
+				     id3_length_t length)
+{
+  id3_ucs4_t padded[31], *data, *end;
+
+  /* latin1 encoding only (this is used for ID3v1 fields) */
+
+  assert(length <= 30);
+
+  data = padded;
+  end  = data + length;
+
+  if (ucs4) {
+    while (*ucs4 && end - data > 0) {
+      *data++ = *ucs4++;
+
+      if (data[-1] == '\n')
+	data[-1] = ' ';
+    }
+  }
+
+  while (end - data > 0)
+    *data++ = ' ';
+
+  *data = 0;
+
+  return length;
+//  return id3_latin1_serialize(ptr, padded, 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/render.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,40 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: render.h,v 1.7 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_RENDER_H
+# define LIBID3TAG_RENDER_H
+
+# include "id3tag.h"
+
+id3_length_t id3_render_immediate(id3_byte_t **, char const *, unsigned int);
+id3_length_t id3_render_syncsafe(id3_byte_t **, unsigned long, unsigned int);
+id3_length_t id3_render_int(id3_byte_t **, signed long, unsigned int);
+id3_length_t id3_render_binary(id3_byte_t **,
+			       id3_byte_t const *, id3_length_t);
+id3_length_t id3_render_latin1(id3_byte_t **, id3_latin1_t const *, int);
+id3_length_t id3_render_string(id3_byte_t **, id3_ucs4_t const *,
+			       enum id3_field_textencoding, int);
+id3_length_t id3_render_padding(id3_byte_t **, id3_byte_t, id3_length_t);
+
+id3_length_t id3_render_paddedstring(id3_byte_t **, id3_ucs4_t const *,
+				     id3_length_t);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/tag.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,912 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: tag.c,v 1.20 2004/02/17 02:04:10 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <string.h>
+# include <stdlib.h>
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include "id3tag.h"
+# include "tag.h"
+# include "frame.h"
+# include "compat.h"
+# include "parse.h"
+# include "render.h"
+# include "latin1.h"
+# include "ucs4.h"
+# include "genre.h"
+# include "crc.h"
+# include "field.h"
+# include "util.h"
+
+/*
+ * NAME:	tag->new()
+ * DESCRIPTION:	allocate and return a new, empty tag
+ */
+struct id3_tag *id3_tag_new(void)
+{
+  struct id3_tag *tag;
+
+  tag = malloc(sizeof(*tag));
+  if (tag) {
+    tag->refcount      = 0;
+    tag->version       = ID3_TAG_VERSION;
+    tag->flags         = 0;
+    tag->extendedflags = 0;
+    tag->restrictions  = 0;
+    tag->options       = /* ID3_TAG_OPTION_UNSYNCHRONISATION | */
+                         ID3_TAG_OPTION_COMPRESSION | ID3_TAG_OPTION_CRC;
+    tag->nframes       = 0;
+    tag->frames        = 0;
+    tag->paddedsize    = 0;
+  }
+
+  return tag;
+}
+
+/*
+ * NAME:	tag->delete()
+ * DESCRIPTION:	destroy a tag and deallocate all associated memory
+ */
+void id3_tag_delete(struct id3_tag *tag)
+{
+  assert(tag);
+
+  if (tag->refcount == 0) {
+    id3_tag_clearframes(tag);
+
+    if (tag->frames)
+      free(tag->frames);
+
+    free(tag);
+  }
+}
+
+/*
+ * NAME:	tag->addref()
+ * DESCRIPTION:	add an external reference to a tag
+ */
+void id3_tag_addref(struct id3_tag *tag)
+{
+  assert(tag);
+
+  ++tag->refcount;
+}
+
+/*
+ * NAME:	tag->delref()
+ * DESCRIPTION:	remove an external reference to a tag
+ */
+void id3_tag_delref(struct id3_tag *tag)
+{
+  assert(tag && tag->refcount > 0);
+
+  --tag->refcount;
+}
+
+/*
+ * NAME:	tag->version()
+ * DESCRIPTION:	return the tag's original ID3 version number
+ */
+unsigned int id3_tag_version(struct id3_tag const *tag)
+{
+  assert(tag);
+
+  return tag->version;
+}
+
+/*
+ * NAME:	tag->options()
+ * DESCRIPTION:	get or set tag options
+ */
+int id3_tag_options(struct id3_tag *tag, int mask, int values)
+{
+  assert(tag);
+
+  if (mask)
+    tag->options = (tag->options & ~mask) | (values & mask);
+
+  return tag->options;
+}
+
+/*
+ * NAME:	tag->setlength()
+ * DESCRIPTION:	set the minimum rendered tag size
+ */
+void id3_tag_setlength(struct id3_tag *tag, id3_length_t length)
+{
+  assert(tag);
+
+  tag->paddedsize = length;
+}
+
+/*
+ * NAME:	tag->clearframes()
+ * DESCRIPTION:	detach and delete all frames associated with a tag
+ */
+void id3_tag_clearframes(struct id3_tag *tag)
+{
+  unsigned int i;
+
+  assert(tag);
+
+  for (i = 0; i < tag->nframes; ++i) {
+    id3_frame_delref(tag->frames[i]);
+    id3_frame_delete(tag->frames[i]);
+  }
+
+  tag->nframes = 0;
+}
+
+/*
+ * NAME:	tag->attachframe()
+ * DESCRIPTION:	attach a frame to a tag
+ */
+int id3_tag_attachframe(struct id3_tag *tag, struct id3_frame *frame)
+{
+  struct id3_frame **frames;
+
+  assert(tag && frame);
+
+  frames = realloc(tag->frames, (tag->nframes + 1) * sizeof(*frames));
+  if (frames == 0)
+    return -1;
+
+  tag->frames = frames;
+  tag->frames[tag->nframes++] = frame;
+
+  id3_frame_addref(frame);
+
+  return 0;
+}
+
+/*
+ * NAME:	tag->detachframe()
+ * DESCRIPTION:	detach (but don't delete) a frame from a tag
+ */
+int id3_tag_detachframe(struct id3_tag *tag, struct id3_frame *frame)
+{
+  unsigned int i;
+
+  assert(tag && frame);
+
+  for (i = 0; i < tag->nframes; ++i) {
+    if (tag->frames[i] == frame)
+      break;
+  }
+
+  if (i == tag->nframes)
+    return -1;
+
+  --tag->nframes;
+  while (i++ < tag->nframes)
+    tag->frames[i - 1] = tag->frames[i];
+
+  id3_frame_delref(frame);
+
+  return 0;
+}
+
+/*
+ * NAME:	tag->findframe()
+ * DESCRIPTION:	find in a tag the nth (0-based) frame with the given frame ID
+ */
+struct id3_frame *id3_tag_findframe(struct id3_tag const *tag,
+				    char const *id, unsigned int index)
+{
+  unsigned int len, i;
+
+  assert(tag);
+
+  if (id == 0 || *id == 0)
+    return (index < tag->nframes) ? tag->frames[index] : 0;
+
+  len = strlen(id);
+
+  if (len == 4) {
+    struct id3_compat const *compat;
+
+    compat = id3_compat_lookup(id, len);
+    if (compat && compat->equiv && !compat->translate) {
+      id  = compat->equiv;
+      len = strlen(id);
+    }
+  }
+
+  for (i = 0; i < tag->nframes; ++i) {
+    if (strncmp(tag->frames[i]->id, id, len) == 0 && index-- == 0)
+      return tag->frames[i];
+  }
+
+  return 0;
+}
+
+enum tagtype {
+  TAGTYPE_NONE = 0,
+  TAGTYPE_ID3V1,
+  TAGTYPE_ID3V2,
+  TAGTYPE_ID3V2_FOOTER
+};
+
+static
+enum tagtype tagtype(id3_byte_t const *data, id3_length_t length)
+{
+  if (length >= 3 &&
+      data[0] == 'T' && data[1] == 'A' && data[2] == 'G')
+    return TAGTYPE_ID3V1;
+
+  if (length >= 10 &&
+      ((data[0] == 'I' && data[1] == 'D' && data[2] == '3') ||
+       (data[0] == '3' && data[1] == 'D' && data[2] == 'I')) &&
+      data[3] < 0xff && data[4] < 0xff &&
+      data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80)
+    return data[0] == 'I' ? TAGTYPE_ID3V2 : TAGTYPE_ID3V2_FOOTER;
+
+  return TAGTYPE_NONE;
+}
+
+static
+void parse_header(id3_byte_t const **ptr,
+		  unsigned int *version, int *flags, id3_length_t *size)
+{
+  *ptr += 3;
+
+  *version = id3_parse_uint(ptr, 2);
+  *flags   = id3_parse_uint(ptr, 1);
+  *size    = id3_parse_syncsafe(ptr, 4);
+}
+
+/*
+ * NAME:	tag->query()
+ * DESCRIPTION:	if a tag begins at the given location, return its size
+ */
+signed long id3_tag_query(id3_byte_t const *data, id3_length_t length)
+{
+  unsigned int version;
+  int flags;
+  id3_length_t size;
+
+  assert(data);
+
+  switch (tagtype(data, length)) {
+  case TAGTYPE_ID3V1:
+    return 128;
+
+  case TAGTYPE_ID3V2:
+    parse_header(&data, &version, &flags, &size);
+
+    if (flags & ID3_TAG_FLAG_FOOTERPRESENT)
+      size += 10;
+
+    return 10 + size;
+
+  case TAGTYPE_ID3V2_FOOTER:
+    parse_header(&data, &version, &flags, &size);
+    return -size - 10;
+
+  case TAGTYPE_NONE:
+    break;
+  }
+
+  return 0;
+}
+
+static
+void trim(char *str)
+{
+  char *ptr;
+
+  ptr = str + strlen(str);
+  while (ptr > str && ptr[-1] == ' ')
+    --ptr;
+
+  *ptr = 0;
+}
+
+static
+int v1_attachstr(struct id3_tag *tag, char const *id,
+		 char *text, unsigned long number)
+{
+  struct id3_frame *frame;
+  id3_ucs4_t ucs4[31];
+
+  if (text) {
+    trim(text);
+    if (*text == 0)
+      return 0;
+  }
+
+  frame = id3_frame_new(id);
+  if (frame == 0)
+    return -1;
+
+  if (id3_field_settextencoding(&frame->fields[0],
+				ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1)
+    goto fail;
+
+  if (text)
+    id3_latin1_decode(text, ucs4);
+  else
+    id3_ucs4_putnumber(ucs4, number);
+
+  if (strcmp(id, ID3_FRAME_COMMENT) == 0) {
+    if (id3_field_setlanguage(&frame->fields[1], "XXX") == -1 ||
+	id3_field_setstring(&frame->fields[2], id3_ucs4_empty) == -1 ||
+	id3_field_setfullstring(&frame->fields[3], ucs4) == -1)
+      goto fail;
+  }
+  else {
+    id3_ucs4_t *ptr = ucs4;
+
+    if (id3_field_setstrings(&frame->fields[1], 1, &ptr) == -1)
+      goto fail;
+  }
+
+  if (id3_tag_attachframe(tag, frame) == -1)
+    goto fail;
+
+  return 0;
+
+ fail:
+  id3_frame_delete(frame);
+  return -1;
+}
+
+static
+struct id3_tag *v1_parse(id3_byte_t const *data)
+{
+  struct id3_tag *tag;
+
+  tag = id3_tag_new();
+  if (tag) {
+    char title[31], artist[31], album[31], year[5], comment[31];
+    unsigned int genre, track;
+
+    tag->version = 0x0100;
+
+    tag->options |=  ID3_TAG_OPTION_ID3V1;
+    tag->options &= ~ID3_TAG_OPTION_COMPRESSION;
+
+    tag->restrictions =
+      ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 |
+      ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS;
+
+    title[30] = artist[30] = album[30] = year[4] = comment[30] = 0;
+
+    memcpy(title,   &data[3],  30);
+    memcpy(artist,  &data[33], 30);
+    memcpy(album,   &data[63], 30);
+    memcpy(year,    &data[93],  4);
+    memcpy(comment, &data[97], 30);
+
+    genre = data[127];
+
+    track = 0;
+    if (comment[28] == 0 && comment[29] != 0) {
+      track = comment[29];
+      tag->version = 0x0101;
+    }
+
+    /* populate tag frames */
+
+    if (v1_attachstr(tag, ID3_FRAME_TITLE,  title,  0) == -1 ||
+	v1_attachstr(tag, ID3_FRAME_ARTIST, artist, 0) == -1 ||
+	v1_attachstr(tag, ID3_FRAME_ALBUM,  album,  0) == -1 ||
+	v1_attachstr(tag, ID3_FRAME_YEAR,   year,   0) == -1 ||
+	(track        && v1_attachstr(tag, ID3_FRAME_TRACK, 0, track) == -1) ||
+	(genre < 0xff && v1_attachstr(tag, ID3_FRAME_GENRE, 0, genre) == -1) ||
+	v1_attachstr(tag, ID3_FRAME_COMMENT, comment, 0) == -1) {
+      id3_tag_delete(tag);
+      tag = 0;
+    }
+  }
+
+  return tag;
+}
+
+static
+struct id3_tag *v2_parse(id3_byte_t const *ptr)
+{
+  struct id3_tag *tag;
+  id3_byte_t *mem = 0;
+
+  tag = id3_tag_new();
+  if (tag) {
+    id3_byte_t const *end;
+    id3_length_t size;
+
+    parse_header(&ptr, &tag->version, &tag->flags, &size);
+
+    tag->paddedsize = 10 + size;
+
+    if ((tag->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) &&
+	ID3_TAG_VERSION_MAJOR(tag->version) < 4) {
+      mem = malloc(size);
+      if (mem == 0)
+	goto fail;
+
+      memcpy(mem, ptr, size);
+
+      size = id3_util_deunsynchronise(mem, size);
+      ptr  = mem;
+    }
+
+    end = ptr + size;
+
+    if (tag->flags & ID3_TAG_FLAG_EXTENDEDHEADER) {
+      switch (ID3_TAG_VERSION_MAJOR(tag->version)) {
+      case 2:
+	goto fail;
+
+      case 3:
+	{
+	  id3_byte_t const *ehptr, *ehend;
+	  id3_length_t ehsize;
+
+	  enum {
+	    EH_FLAG_CRC = 0x8000  /* CRC data present */
+	  };
+
+	  if (end - ptr < 4)
+	    goto fail;
+
+	  ehsize = id3_parse_uint(&ptr, 4);
+
+	  if (ehsize > end - ptr)
+	    goto fail;
+
+	  ehptr = ptr;
+	  ehend = ptr + ehsize;
+
+	  ptr = ehend;
+
+	  if (ehend - ehptr >= 6) {
+	    int ehflags;
+	    id3_length_t padsize;
+
+	    ehflags = id3_parse_uint(&ehptr, 2);
+	    padsize = id3_parse_uint(&ehptr, 4);
+
+	    if (padsize > end - ptr)
+	      goto fail;
+
+	    end -= padsize;
+
+	    if (ehflags & EH_FLAG_CRC) {
+	      unsigned long crc;
+
+	      if (ehend - ehptr < 4)
+		goto fail;
+
+	      crc = id3_parse_uint(&ehptr, 4);
+
+	      if (crc != id3_crc_compute(ptr, end - ptr))
+		goto fail;
+
+	      tag->extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT;
+	    }
+	  }
+	}
+	break;
+
+      case 4:
+	{
+	  id3_byte_t const *ehptr, *ehend;
+	  id3_length_t ehsize;
+	  unsigned int bytes;
+
+	  if (end - ptr < 4)
+	    goto fail;
+
+	  ehptr  = ptr;
+	  ehsize = id3_parse_syncsafe(&ptr, 4);
+
+	  if (ehsize < 6 || ehsize > end - ehptr)
+	    goto fail;
+
+	  ehend = ehptr + ehsize;
+
+	  bytes = id3_parse_uint(&ptr, 1);
+
+	  if (bytes < 1 || bytes > ehend - ptr)
+	    goto fail;
+
+	  ehptr = ptr + bytes;
+
+	  /* verify extended header size */
+	  {
+	    id3_byte_t const *flagsptr = ptr, *dataptr = ehptr;
+	    unsigned int datalen;
+	    int ehflags;
+
+	    while (bytes--) {
+	      for (ehflags = id3_parse_uint(&flagsptr, 1); ehflags;
+		   ehflags = (ehflags << 1) & 0xff) {
+		if (ehflags & 0x80) {
+		  if (dataptr == ehend)
+		    goto fail;
+		  datalen = id3_parse_uint(&dataptr, 1);
+		  if (datalen > 0x7f || datalen > ehend - dataptr)
+		    goto fail;
+		  dataptr += datalen;
+		}
+	      }
+	    }
+	  }
+
+	  tag->extendedflags = id3_parse_uint(&ptr, 1);
+
+	  ptr = ehend;
+
+	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) {
+	    bytes  = id3_parse_uint(&ehptr, 1);
+	    ehptr += bytes;
+	  }
+
+	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) {
+	    unsigned long crc;
+
+	    bytes = id3_parse_uint(&ehptr, 1);
+	    if (bytes < 5)
+	      goto fail;
+
+	    crc = id3_parse_syncsafe(&ehptr, 5);
+	    ehptr += bytes - 5;
+
+	    if (crc != id3_crc_compute(ptr, end - ptr))
+	      goto fail;
+	  }
+
+	  if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) {
+	    bytes = id3_parse_uint(&ehptr, 1);
+	    if (bytes < 1)
+	      goto fail;
+
+	    tag->restrictions = id3_parse_uint(&ehptr, 1);
+	    ehptr += bytes - 1;
+	  }
+	}
+	break;
+      }
+    }
+
+    /* frames */
+
+    while (ptr < end) {
+      struct id3_frame *frame;
+
+      if (*ptr == 0)
+	break;  /* padding */
+
+      frame = id3_frame_parse(&ptr, end - ptr, tag->version);
+      if (frame == 0 || id3_tag_attachframe(tag, frame) == -1)
+	goto fail;
+    }
+
+    if (ID3_TAG_VERSION_MAJOR(tag->version) < 4 &&
+	id3_compat_fixup(tag) == -1)
+      goto fail;
+  }
+
+  if (0) {
+  fail:
+    id3_tag_delete(tag);
+    tag = 0;
+  }
+
+  if (mem)
+    free(mem);
+
+  return tag;
+}
+
+/*
+ * NAME:	tag->parse()
+ * DESCRIPTION:	parse a complete ID3 tag
+ */
+struct id3_tag *id3_tag_parse(id3_byte_t const *data, id3_length_t length)
+{
+  id3_byte_t const *ptr;
+  unsigned int version;
+  int flags;
+  id3_length_t size;
+
+  assert(data);
+
+  switch (tagtype(data, length)) {
+  case TAGTYPE_ID3V1:
+    return (length < 128) ? 0 : v1_parse(data);
+
+  case TAGTYPE_ID3V2:
+    break;
+
+  case TAGTYPE_ID3V2_FOOTER:
+  case TAGTYPE_NONE:
+    return 0;
+  }
+
+  /* ID3v2.x */
+
+  ptr = data;
+  parse_header(&ptr, &version, &flags, &size);
+
+  switch (ID3_TAG_VERSION_MAJOR(version)) {
+  case 4:
+    if (flags & ID3_TAG_FLAG_FOOTERPRESENT)
+      size += 10;
+  case 2:
+  case 3:
+    return (length < 10 + size) ? 0 : v2_parse(data);
+  }
+
+  return 0;
+}
+
+static
+void v1_renderstr(struct id3_tag const *tag, char const *frameid,
+		  id3_byte_t **buffer, id3_length_t length)
+{
+  struct id3_frame *frame;
+  id3_ucs4_t const *string;
+
+  frame = id3_tag_findframe(tag, frameid, 0);
+  if (frame == 0)
+    string = id3_ucs4_empty;
+  else {
+    if (strcmp(frameid, ID3_FRAME_COMMENT) == 0)
+      string = id3_field_getfullstring(&frame->fields[3]);
+    else
+      string = id3_field_getstrings(&frame->fields[1], 0);
+  }
+
+  id3_render_paddedstring(buffer, string, length);
+}
+
+/*
+ * NAME:	v1->render()
+ * DESCRIPTION:	render an ID3v1 (or ID3v1.1) tag
+ */
+static
+id3_length_t v1_render(struct id3_tag const *tag, id3_byte_t *buffer)
+{
+  id3_byte_t data[128], *ptr;
+  struct id3_frame *frame;
+  unsigned int i;
+  int genre = -1;
+
+  ptr = data;
+
+  id3_render_immediate(&ptr, "TAG", 3);
+
+  v1_renderstr(tag, ID3_FRAME_TITLE,   &ptr, 30);
+  v1_renderstr(tag, ID3_FRAME_ARTIST,  &ptr, 30);
+  v1_renderstr(tag, ID3_FRAME_ALBUM,   &ptr, 30);
+  v1_renderstr(tag, ID3_FRAME_YEAR,    &ptr,  4);
+  v1_renderstr(tag, ID3_FRAME_COMMENT, &ptr, 30);
+
+  /* ID3v1.1 track number */
+
+  frame = id3_tag_findframe(tag, ID3_FRAME_TRACK, 0);
+  if (frame) {
+    id3_ucs4_t const *string;
+    unsigned int track = 0;
+
+	string = id3_field_getstrings(&frame->fields[1], 0);
+	if (string)
+    	track = id3_ucs4_getnumber(string);
+    if (track > 0 && track <= 0xff) {
+      ptr[-2] = 0;
+      ptr[-1] = track;
+    }
+  }
+
+  /* ID3v1 genre number */
+
+  frame = id3_tag_findframe(tag, ID3_FRAME_GENRE, 0);
+  if (frame) {
+    unsigned int nstrings;
+
+    nstrings = id3_field_getnstrings(&frame->fields[1]);
+
+    for (i = 0; i < nstrings; ++i) {
+      genre = id3_genre_number(id3_field_getstrings(&frame->fields[1], i));
+      if (genre != -1)
+	break;
+    }
+
+    if (i == nstrings && nstrings > 0)
+      genre = ID3_GENRE_OTHER;
+  }
+
+  id3_render_int(&ptr, genre, 1);
+
+  /* make sure the tag is not empty */
+
+  if (genre == -1) {
+    for (i = 3; i < 127; ++i) {
+      if (data[i] != ' ')
+	break;
+    }
+
+    if (i == 127)
+      return 0;
+  }
+
+  if (buffer)
+    memcpy(buffer, data, 128);
+
+  return 128;
+}
+
+/*
+ * NAME:	tag->render()
+ * DESCRIPTION:	render a complete ID3 tag
+ */
+id3_length_t id3_tag_render(struct id3_tag const *tag, id3_byte_t *buffer)
+{
+  id3_length_t size = 0;
+  id3_byte_t **ptr,
+    *header_ptr = 0, *tagsize_ptr = 0, *crc_ptr = 0, *frames_ptr = 0;
+  int flags, extendedflags;
+  unsigned int i;
+
+  assert(tag);
+
+  if (tag->options & ID3_TAG_OPTION_ID3V1)
+    return v1_render(tag, buffer);
+
+  /* a tag must contain at least one (renderable) frame */
+
+  for (i = 0; i < tag->nframes; ++i) {
+    if (id3_frame_render(tag->frames[i], 0, 0) > 0)
+      break;
+  }
+
+  if (i == tag->nframes)
+    return 0;
+
+  ptr = buffer ? &buffer : 0;
+
+  /* get flags */
+
+  flags         = tag->flags         & ID3_TAG_FLAG_KNOWNFLAGS;
+  extendedflags = tag->extendedflags & ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS;
+
+  extendedflags &= ~ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT;
+  if (tag->options & ID3_TAG_OPTION_CRC)
+    extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT;
+
+  extendedflags &= ~ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS;
+  if (tag->restrictions)
+    extendedflags |= ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS;
+
+  flags &= ~ID3_TAG_FLAG_UNSYNCHRONISATION;
+  if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION)
+    flags |= ID3_TAG_FLAG_UNSYNCHRONISATION;
+
+  flags &= ~ID3_TAG_FLAG_EXTENDEDHEADER;
+  if (extendedflags)
+    flags |= ID3_TAG_FLAG_EXTENDEDHEADER;
+
+  flags &= ~ID3_TAG_FLAG_FOOTERPRESENT;
+  if (tag->options & ID3_TAG_OPTION_APPENDEDTAG)
+    flags |= ID3_TAG_FLAG_FOOTERPRESENT;
+
+  /* header */
+
+  if (ptr)
+    header_ptr = *ptr;
+
+  size += id3_render_immediate(ptr, "ID3", 3);
+  size += id3_render_int(ptr, ID3_TAG_VERSION, 2);
+  size += id3_render_int(ptr, flags, 1);
+
+  if (ptr)
+    tagsize_ptr = *ptr;
+
+  size += id3_render_syncsafe(ptr, 0, 4);
+
+  /* extended header */
+
+  if (flags & ID3_TAG_FLAG_EXTENDEDHEADER) {
+    id3_length_t ehsize = 0;
+    id3_byte_t *ehsize_ptr = 0;
+
+    if (ptr)
+      ehsize_ptr = *ptr;
+
+    ehsize += id3_render_syncsafe(ptr, 0, 4);
+    ehsize += id3_render_int(ptr, 1, 1);
+    ehsize += id3_render_int(ptr, extendedflags, 1);
+
+    if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)
+      ehsize += id3_render_int(ptr, 0, 1);
+
+    if (extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) {
+      ehsize += id3_render_int(ptr, 5, 1);
+
+      if (ptr)
+	crc_ptr = *ptr;
+
+      ehsize += id3_render_syncsafe(ptr, 0, 5);
+    }
+
+    if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) {
+      ehsize += id3_render_int(ptr, 1, 1);
+      ehsize += id3_render_int(ptr, tag->restrictions, 1);
+    }
+
+    if (ehsize_ptr)
+      id3_render_syncsafe(&ehsize_ptr, ehsize, 4);
+
+    size += ehsize;
+  }
+
+  /* frames */
+
+  if (ptr)
+    frames_ptr = *ptr;
+
+  for (i = 0; i < tag->nframes; ++i)
+    size += id3_frame_render(tag->frames[i], ptr, tag->options);
+
+  /* padding */
+
+  if (!(flags & ID3_TAG_FLAG_FOOTERPRESENT)) {
+    if (size < tag->paddedsize)
+      size += id3_render_padding(ptr, 0, tag->paddedsize - size);
+    else if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION) {
+      if (ptr == 0)
+	size += 1;
+      else {
+	if ((*ptr)[-1] == 0xff)
+	  size += id3_render_padding(ptr, 0, 1);
+      }
+    }
+  }
+
+  /* patch tag size and CRC */
+
+  if (tagsize_ptr)
+    id3_render_syncsafe(&tagsize_ptr, size - 10, 4);
+
+  if (crc_ptr) {
+    id3_render_syncsafe(&crc_ptr,
+			id3_crc_compute(frames_ptr, *ptr - frames_ptr), 5);
+  }
+
+  /* footer */
+
+  if (flags & ID3_TAG_FLAG_FOOTERPRESENT) {
+    size += id3_render_immediate(ptr, "3DI", 3);
+    size += id3_render_binary(ptr, header_ptr + 3, 7);
+  }
+
+  return size;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/tag.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,30 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: tag.h,v 1.10 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_TAG_H
+# define LIBID3TAG_TAG_H
+
+# include "id3tag.h"
+
+void id3_tag_addref(struct id3_tag *);
+void id3_tag_delref(struct id3_tag *);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/ucs4.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,290 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: ucs4.c,v 1.13 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+
+# include "id3tag.h"
+# include "ucs4.h"
+# include "latin1.h"
+# include "utf16.h"
+# include "utf8.h"
+
+id3_ucs4_t const id3_ucs4_empty[] = { 0 };
+
+/*
+ * NAME:	ucs4->length()
+ * DESCRIPTION:	return the number of ucs4 chars represented by a ucs4 string
+ */
+id3_length_t id3_ucs4_length(id3_ucs4_t const *ucs4)
+{
+  id3_ucs4_t const *ptr = ucs4;
+
+  while (*ptr)
+    ++ptr;
+
+  return ptr - ucs4;
+}
+
+/*
+ * NAME:	ucs4->size()
+ * DESCRIPTION:	return the encoding size of a ucs4 string
+ */
+id3_length_t id3_ucs4_size(id3_ucs4_t const *ucs4)
+{
+  return id3_ucs4_length(ucs4) + 1;
+}
+
+/*
+ * NAME:	ucs4->latin1size()
+ * DESCRIPTION:	return the encoding size of a latin1-encoded ucs4 string
+ */
+id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *ucs4)
+{
+  return id3_ucs4_size(ucs4);
+}
+
+/*
+ * NAME:	ucs4->utf16size()
+ * DESCRIPTION:	return the encoding size of a utf16-encoded ucs4 string
+ */
+id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *ucs4)
+{
+  id3_length_t size = 0;
+
+  while (*ucs4) {
+    ++size;
+    if (*ucs4 >= 0x00010000L &&
+	*ucs4 <= 0x0010ffffL)
+      ++size;
+
+    ++ucs4;
+  }
+
+  return size + 1;
+}
+
+/*
+ * NAME:	ucs4->utf8size()
+ * DESCRIPTION:	return the encoding size of a utf8-encoded ucs4 string
+ */
+id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *ucs4)
+{
+  id3_length_t size = 0;
+
+  while (*ucs4) {
+    if (*ucs4 <= 0x0000007fL)
+      size += 1;
+    else if (*ucs4 <= 0x000007ffL)
+      size += 2;
+    else if (*ucs4 <= 0x0000ffffL)
+      size += 3;
+    else if (*ucs4 <= 0x001fffffL)
+      size += 4;
+    else if (*ucs4 <= 0x03ffffffL)
+      size += 5;
+    else if (*ucs4 <= 0x7fffffffL)
+      size += 6;
+    else
+      size += 2;  /* based on U+00B7 replacement char */
+
+    ++ucs4;
+  }
+
+  return size + 1;
+}
+
+/*
+ * NAME:	ucs4->utf8size()
+ * DESCRIPTION:	return the encoding size of a utf8-encoded ucs4 string
+ */
+id3_length_t id3_ucs4_multibytesize(id3_ucs4_t const *ucs4)
+{
+  id3_length_t size = 0;
+
+  while (*ucs4) {
+    if (*ucs4 <= 0x0000007fL)
+      size += 1;
+    else if (*ucs4 <= 0x000007ffL)
+      size += 2;
+    else if (*ucs4 <= 0x0000ffffL)
+      size += 3;
+    else if (*ucs4 <= 0x001fffffL)
+      size += 4;
+    else if (*ucs4 <= 0x03ffffffL)
+      size += 5;
+    else if (*ucs4 <= 0x7fffffffL)
+      size += 6;
+    else
+      size += 2;  /* based on U+00B7 replacement char */
+
+    ++ucs4;
+  }
+
+  return size + 1;
+}
+
+/*
+ * NAME:	ucs4->latin1duplicate()
+ * DESCRIPTION:	duplicate and encode a ucs4 string into latin1
+ */
+id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *ucs4)
+{
+  id3_latin1_t *latin1;
+
+  latin1 = malloc(id3_ucs4_latin1size(ucs4) * sizeof(*latin1));
+  if (latin1)
+    id3_latin1_encode(latin1, ucs4);
+
+  return release(latin1);
+}
+
+/*
+ * NAME:	ucs4->utf16duplicate()
+ * DESCRIPTION:	duplicate and encode a ucs4 string into utf16
+ */
+id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *ucs4)
+{
+  id3_utf16_t *utf16;
+
+  utf16 = malloc(id3_ucs4_utf16size(ucs4) * sizeof(*utf16));
+  if (utf16)
+    id3_utf16_encode(utf16, ucs4);
+
+  return release(utf16);
+}
+
+/*
+ * NAME:	ucs4->utf8duplicate()
+ * DESCRIPTION:	duplicate and encode a ucs4 string into utf8
+ */
+id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *ucs4)
+{
+  id3_utf8_t *utf8;
+
+  utf8 = malloc(id3_ucs4_utf8size(ucs4) * sizeof(*utf8));
+  if (utf8)
+    id3_utf8_encode(utf8, ucs4);
+
+  return release(utf8);
+}
+
+#if 0
+void id3_multibyte_encode(id3_latin1_t *multi, id3_ucs4_t const *ucs4)
+{
+    id3_latin1_t *mptr;
+    id3_ucs4_t *uptr;
+    int multi
+    //prescan
+
+    // 1. if threre is multi byte entry, the string must be multi byte unicode string.
+    //    -> convert into utf-8
+    // 2. if thre is no multi byte entry and there is a single byte character 
+
+        the string is in locale specific encoding or 
+
+    if(*uptr < 
+
+    *mptr = 
+
+    
+}
+
+/*
+ * NAME:	ucs4->utf8duplicate()
+ * DESCRIPTION:	duplicate and encode a ucs4 string into utf8
+ */
+id3_utf8_t *id3_ucs4_multibyteduplicate(id3_ucs4_t const *ucs4)
+{
+  id3_latin1_t *multi;
+  multi = malloc(id3_ucs4_multibytesize(ucs4) * sizeof(*utf8));
+  if (multi)
+    id3_multibyte_encode(multi, ucs4);
+
+  return release(multi);
+}
+#endif
+
+/*
+ * NAME:	ucs4->copy()
+ * DESCRIPTION:	copy a ucs4 string
+ */
+void id3_ucs4_copy(id3_ucs4_t *dest, id3_ucs4_t const *src)
+{
+  while ((*dest++ = *src++))
+    ;
+}
+
+/*
+ * NAME:	ucs4->duplicate()
+ * DESCRIPTION:	duplicate a ucs4 string
+ */
+id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *src)
+{
+  id3_ucs4_t *ucs4;
+
+  ucs4 = malloc(id3_ucs4_size(src) * sizeof(*ucs4));
+  if (ucs4)
+    id3_ucs4_copy(ucs4, src);
+
+  return ucs4;
+}
+
+/*
+ * NAME:	ucs4->putnumber()
+ * DESCRIPTION:	write a ucs4 string containing a (positive) decimal number
+ */
+void id3_ucs4_putnumber(id3_ucs4_t *ucs4, unsigned long number)
+{
+  int digits[10], *digit;
+
+  digit = digits;
+
+  do {
+    *digit++ = number % 10;
+    number  /= 10;
+  }
+  while (number);
+
+  while (digit != digits)
+    *ucs4++ = '0' + *--digit;
+
+  *ucs4 = 0;
+}
+
+/*
+ * NAME:	ucs4->getnumber()
+ * DESCRIPTION:	read a ucs4 string containing a (positive) decimal number
+ */
+unsigned long id3_ucs4_getnumber(id3_ucs4_t const *ucs4)
+{
+  unsigned long number = 0;
+
+  while (*ucs4 >= '0' && *ucs4 <= '9')
+    number = 10 * number + (*ucs4++ - '0');
+
+  return number;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/ucs4.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,41 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: ucs4.h,v 1.11 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_UCS4_H
+# define LIBID3TAG_UCS4_H
+
+# include "id3tag.h"
+
+# define ID3_UCS4_REPLACEMENTCHAR  0x000000b7L  /* middle dot */
+
+extern id3_ucs4_t const id3_ucs4_empty[];
+
+id3_length_t id3_ucs4_length(id3_ucs4_t const *);
+id3_length_t id3_ucs4_size(id3_ucs4_t const *);
+
+id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *);
+id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *);
+id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *);
+
+void id3_ucs4_copy(id3_ucs4_t *, id3_ucs4_t const *);
+id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/utf16.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,286 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: utf16.c,v 1.9 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+
+# include "id3tag.h"
+# include "utf16.h"
+# include "ucs4.h"
+
+/*
+ * NAME:	utf16->length()
+ * DESCRIPTION:	return the number of ucs4 chars represented by a utf16 string
+ */
+id3_length_t id3_utf16_length(id3_utf16_t const *utf16)
+{
+  id3_length_t length = 0;
+
+  while (*utf16) {
+    if (utf16[0] < 0xd800 || utf16[0] > 0xdfff)
+      ++length;
+    else if (utf16[0] >= 0xd800 && utf16[0] <= 0xdbff &&
+	     utf16[1] >= 0xdc00 && utf16[1] <= 0xdfff) {
+      ++length;
+      ++utf16;
+    }
+
+    ++utf16;
+  }
+
+  return length;
+}
+
+/*
+ * NAME:	utf16->size()
+ * DESCRIPTION:	return the encoding size of a utf16 string
+ */
+id3_length_t id3_utf16_size(id3_utf16_t const *utf16)
+{
+  id3_utf16_t const *ptr = utf16;
+
+  while (*ptr)
+    ++ptr;
+
+  return ptr - utf16 + 1;
+}
+
+/*
+ * NAME:	utf16->ucs4duplicate()
+ * DESCRIPTION:	duplicate and decode a utf16 string into ucs4
+ */
+id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *utf16)
+{
+  id3_ucs4_t *ucs4;
+
+  ucs4 = malloc((id3_utf16_length(utf16) + 1) * sizeof(*ucs4));
+  if (ucs4)
+    id3_utf16_decode(utf16, ucs4);
+
+  return release(ucs4);
+}
+
+/*
+ * NAME:	utf16->decodechar()
+ * DESCRIPTION:	decode a series of utf16 chars into a single ucs4 char
+ */
+id3_length_t id3_utf16_decodechar(id3_utf16_t const *utf16, id3_ucs4_t *ucs4)
+{
+  id3_utf16_t const *start = utf16;
+
+  while (1) {
+    if (utf16[0] < 0xd800 || utf16[0] > 0xdfff) {
+      *ucs4 = utf16[0];
+      return utf16 - start + 1;
+    }
+    else if (utf16[0] >= 0xd800 && utf16[0] <= 0xdbff &&
+	     utf16[1] >= 0xdc00 && utf16[1] <= 0xdfff) {
+      *ucs4 = (((utf16[0] & 0x03ffL) << 10) |
+	       ((utf16[1] & 0x03ffL) <<  0)) + 0x00010000L;
+      return utf16 - start + 2;
+    }
+
+    ++utf16;
+  }
+}
+
+/*
+ * NAME:	utf16->encodechar()
+ * DESCRIPTION:	encode a single ucs4 char into a series of up to 2 utf16 chars
+ */
+id3_length_t id3_utf16_encodechar(id3_utf16_t *utf16, id3_ucs4_t ucs4)
+{
+  if (ucs4 < 0x00010000L) {
+    utf16[0] = ucs4;
+
+    return 1;
+  }
+  else if (ucs4 < 0x00110000L) {
+    ucs4 -= 0x00010000L;
+
+    utf16[0] = ((ucs4 >> 10) & 0x3ff) | 0xd800;
+    utf16[1] = ((ucs4 >>  0) & 0x3ff) | 0xdc00;
+
+    return 2;
+  }
+
+  /* default */
+
+  return id3_utf16_encodechar(utf16, ID3_UCS4_REPLACEMENTCHAR);
+}
+
+/*
+ * NAME:	utf16->decode()
+ * DESCRIPTION:	decode a complete utf16 string into a ucs4 string
+ */
+void id3_utf16_decode(id3_utf16_t const *utf16, id3_ucs4_t *ucs4)
+{
+  do
+    utf16 += id3_utf16_decodechar(utf16, ucs4);
+  while (*ucs4++);
+}
+
+/*
+ * NAME:	utf16->encode()
+ * DESCRIPTION:	encode a complete ucs4 string into a utf16 string
+ */
+void id3_utf16_encode(id3_utf16_t *utf16, id3_ucs4_t const *ucs4)
+{
+  do
+    utf16 += id3_utf16_encodechar(utf16, *ucs4);
+  while (*ucs4++);
+}
+
+/*
+ * NAME:	utf16->put()
+ * DESCRIPTION:	serialize a single utf16 character
+ */
+id3_length_t id3_utf16_put(id3_byte_t **ptr, id3_utf16_t utf16,
+			   enum id3_utf16_byteorder byteorder)
+{
+  if (ptr) {
+    switch (byteorder) {
+    default:
+    case ID3_UTF16_BYTEORDER_BE:
+      (*ptr)[0] = (utf16 >> 8) & 0xff;
+      (*ptr)[1] = (utf16 >> 0) & 0xff;
+      break;
+
+    case ID3_UTF16_BYTEORDER_LE:
+      (*ptr)[0] = (utf16 >> 0) & 0xff;
+      (*ptr)[1] = (utf16 >> 8) & 0xff;
+      break;
+    }
+
+    *ptr += 2;
+  }
+
+  return 2;
+}
+
+/*
+ * NAME:	utf16->get()
+ * DESCRIPTION:	deserialize a single utf16 character
+ */
+id3_utf16_t id3_utf16_get(id3_byte_t const **ptr,
+			  enum id3_utf16_byteorder byteorder)
+{
+  id3_utf16_t utf16;
+
+  switch (byteorder) {
+  default:
+  case ID3_UTF16_BYTEORDER_BE:
+    utf16 =
+      ((*ptr)[0] << 8) |
+      ((*ptr)[1] << 0);
+    break;
+
+  case ID3_UTF16_BYTEORDER_LE:
+    utf16 =
+      ((*ptr)[0] << 0) |
+      ((*ptr)[1] << 8);
+    break;
+  }
+
+  *ptr += 2;
+
+  return utf16;
+}
+
+/*
+ * NAME:	utf16->serialize()
+ * DESCRIPTION:	serialize a ucs4 string using utf16 encoding
+ */
+id3_length_t id3_utf16_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4,
+				 enum id3_utf16_byteorder byteorder,
+				 int terminate)
+{
+  id3_length_t size = 0;
+  id3_utf16_t utf16[2], *out;
+
+  if (byteorder == ID3_UTF16_BYTEORDER_ANY)
+    size += id3_utf16_put(ptr, 0xfeff, byteorder);
+
+  while (*ucs4) {
+    switch (id3_utf16_encodechar(out = utf16, *ucs4++)) {
+    case 2: size += id3_utf16_put(ptr, *out++, byteorder);
+    case 1: size += id3_utf16_put(ptr, *out++, byteorder);
+    case 0: break;
+    }
+  }
+
+  if (terminate)
+    size += id3_utf16_put(ptr, 0, byteorder);
+
+  return size;
+}
+
+/*
+ * NAME:	utf16->deserialize()
+ * DESCRIPTION:	deserialize a ucs4 string using utf16 encoding
+ */
+id3_ucs4_t *id3_utf16_deserialize(id3_byte_t const **ptr, id3_length_t length,
+				  enum id3_utf16_byteorder byteorder)
+{
+  id3_byte_t const *end;
+  id3_utf16_t *utf16ptr, *utf16;
+  id3_ucs4_t *ucs4;
+
+  end = *ptr + (length & ~1);
+
+  utf16 = malloc((length / 2 + 1) * sizeof(*utf16));
+  if (utf16 == 0)
+    return 0;
+
+  if (byteorder == ID3_UTF16_BYTEORDER_ANY && end - *ptr > 0) {
+    switch (((*ptr)[0] << 8) |
+	    ((*ptr)[1] << 0)) {
+    case 0xfeff:
+      byteorder = ID3_UTF16_BYTEORDER_BE;
+      *ptr += 2;
+      break;
+
+    case 0xfffe:
+      byteorder = ID3_UTF16_BYTEORDER_LE;
+      *ptr += 2;
+      break;
+    }
+  }
+
+  utf16ptr = utf16;
+  while (end - *ptr > 0 && (*utf16ptr = id3_utf16_get(ptr, byteorder)))
+    ++utf16ptr;
+
+  *utf16ptr = 0;
+
+  ucs4 = malloc((id3_utf16_length(utf16) + 1) * sizeof(*ucs4));
+  if (ucs4)
+    id3_utf16_decode(utf16, ucs4);
+
+  free(utf16);
+
+  return ucs4;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/utf16.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,51 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: utf16.h,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_UTF16_H
+# define LIBID3TAG_UTF16_H
+
+# include "id3tag.h"
+
+enum id3_utf16_byteorder {
+  ID3_UTF16_BYTEORDER_ANY,
+  ID3_UTF16_BYTEORDER_BE,
+  ID3_UTF16_BYTEORDER_LE
+};
+
+id3_length_t id3_utf16_length(id3_utf16_t const *);
+id3_length_t id3_utf16_size(id3_utf16_t const *);
+
+id3_length_t id3_utf16_decodechar(id3_utf16_t const *, id3_ucs4_t *);
+id3_length_t id3_utf16_encodechar(id3_utf16_t *, id3_ucs4_t);
+
+void id3_utf16_decode(id3_utf16_t const *, id3_ucs4_t *);
+void id3_utf16_encode(id3_utf16_t *, id3_ucs4_t const *);
+
+id3_length_t id3_utf16_put(id3_byte_t **, id3_utf16_t,
+			   enum id3_utf16_byteorder);
+id3_utf16_t id3_utf16_get(id3_byte_t const **, enum id3_utf16_byteorder);
+
+id3_length_t id3_utf16_serialize(id3_byte_t **, id3_ucs4_t const *,
+				 enum id3_utf16_byteorder, int);
+id3_ucs4_t *id3_utf16_deserialize(id3_byte_t const **, id3_length_t,
+				  enum id3_utf16_byteorder);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/utf8.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,365 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: utf8.c,v 1.9 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+
+# include "id3tag.h"
+# include "utf8.h"
+# include "ucs4.h"
+
+/*
+ * NAME:	utf8->length()
+ * DESCRIPTION:	return the number of ucs4 chars represented by a utf8 string
+ */
+id3_length_t id3_utf8_length(id3_utf8_t const *utf8)
+{
+  id3_length_t length = 0;
+
+  while (*utf8) {
+    if ((utf8[0] & 0x80) == 0x00)
+      ++length;
+    else if ((utf8[0] & 0xe0) == 0xc0 &&
+	     (utf8[1] & 0xc0) == 0x80) {
+      if (((utf8[0] & 0x1fL) << 6) >= 0x00000080L) {
+	++length;
+	utf8 += 1;
+      }
+    }
+    else if ((utf8[0] & 0xf0) == 0xe0 &&
+	     (utf8[1] & 0xc0) == 0x80 &&
+	     (utf8[2] & 0xc0) == 0x80) {
+      if ((((utf8[0] & 0x0fL) << 12) |
+	   ((utf8[1] & 0x3fL) <<  6)) >= 0x00000800L) {
+	++length;
+	utf8 += 2;
+      }
+    }
+    else if ((utf8[0] & 0xf8) == 0xf0 &&
+	     (utf8[1] & 0xc0) == 0x80 &&
+	     (utf8[2] & 0xc0) == 0x80 &&
+	     (utf8[3] & 0xc0) == 0x80) {
+      if ((((utf8[0] & 0x07L) << 18) |
+	   ((utf8[1] & 0x3fL) << 12)) >= 0x00010000L) {
+	++length;
+	utf8 += 3;
+      }
+    }
+    else if ((utf8[0] & 0xfc) == 0xf8 &&
+	     (utf8[1] & 0xc0) == 0x80 &&
+	     (utf8[2] & 0xc0) == 0x80 &&
+	     (utf8[3] & 0xc0) == 0x80 &&
+	     (utf8[4] & 0xc0) == 0x80) {
+      if ((((utf8[0] & 0x03L) << 24) |
+	   ((utf8[0] & 0x3fL) << 18)) >= 0x00200000L) {
+	++length;
+	utf8 += 4;
+      }
+    }
+    else if ((utf8[0] & 0xfe) == 0xfc &&
+	     (utf8[1] & 0xc0) == 0x80 &&
+	     (utf8[2] & 0xc0) == 0x80 &&
+	     (utf8[3] & 0xc0) == 0x80 &&
+	     (utf8[4] & 0xc0) == 0x80 &&
+	     (utf8[5] & 0xc0) == 0x80) {
+      if ((((utf8[0] & 0x01L) << 30) |
+	   ((utf8[0] & 0x3fL) << 24)) >= 0x04000000L) {
+	++length;
+	utf8 += 5;
+      }
+    }
+
+    ++utf8;
+  }
+
+  return length;
+}
+
+/*
+ * NAME:	utf8->size()
+ * DESCRIPTION:	return the encoding size of a utf8 string
+ */
+id3_length_t id3_utf8_size(id3_utf8_t const *utf8)
+{
+  id3_utf8_t const *ptr = utf8;
+
+  while (*ptr)
+    ++ptr;
+
+  return ptr - utf8 + 1;
+}
+
+/*
+ * NAME:	utf8->ucs4duplicate()
+ * DESCRIPTION:	duplicate and decode a utf8 string into ucs4
+ */
+id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *utf8)
+{
+  id3_ucs4_t *ucs4;
+
+  ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4));
+  if (ucs4)
+    id3_utf8_decode(utf8, ucs4);
+
+  return release(ucs4);
+}
+
+/*
+ * NAME:	utf8->decodechar()
+ * DESCRIPTION:	decode a series of utf8 chars into a single ucs4 char
+ */
+id3_length_t id3_utf8_decodechar(id3_utf8_t const *utf8, id3_ucs4_t *ucs4)
+{
+  id3_utf8_t const *start = utf8;
+
+  while (1) {
+    if ((utf8[0] & 0x80) == 0x00) {
+      *ucs4 = utf8[0];
+      return utf8 - start + 1;
+    }
+    else if ((utf8[0] & 0xe0) == 0xc0 &&
+	     (utf8[1] & 0xc0) == 0x80) {
+      *ucs4 =
+	((utf8[0] & 0x1fL) << 6) |
+	((utf8[1] & 0x3fL) << 0);
+      if (*ucs4 >= 0x00000080L)
+	return utf8 - start + 2;
+    }
+    else if ((utf8[0] & 0xf0) == 0xe0 &&
+	     (utf8[1] & 0xc0) == 0x80 &&
+	     (utf8[2] & 0xc0) == 0x80) {
+      *ucs4 =
+	((utf8[0] & 0x0fL) << 12) |
+	((utf8[1] & 0x3fL) <<  6) |
+	((utf8[2] & 0x3fL) <<  0);
+      if (*ucs4 >= 0x00000800L)
+	return utf8 - start + 3;
+    }
+    else if ((utf8[0] & 0xf8) == 0xf0 &&
+	     (utf8[1] & 0xc0) == 0x80 &&
+	     (utf8[2] & 0xc0) == 0x80 &&
+	     (utf8[3] & 0xc0) == 0x80) {
+      *ucs4 =
+	((utf8[0] & 0x07L) << 18) |
+	((utf8[1] & 0x3fL) << 12) |
+	((utf8[2] & 0x3fL) <<  6) |
+	((utf8[3] & 0x3fL) <<  0);
+      if (*ucs4 >= 0x00010000L)
+	return utf8 - start + 4;
+    }
+    else if ((utf8[0] & 0xfc) == 0xf8 &&
+	     (utf8[1] & 0xc0) == 0x80 &&
+	     (utf8[2] & 0xc0) == 0x80 &&
+	     (utf8[3] & 0xc0) == 0x80 &&
+	     (utf8[4] & 0xc0) == 0x80) {
+      *ucs4 =
+	((utf8[0] & 0x03L) << 24) |
+	((utf8[1] & 0x3fL) << 18) |
+	((utf8[2] & 0x3fL) << 12) |
+	((utf8[3] & 0x3fL) <<  6) |
+	((utf8[4] & 0x3fL) <<  0);
+      if (*ucs4 >= 0x00200000L)
+	return utf8 - start + 5;
+    }
+    else if ((utf8[0] & 0xfe) == 0xfc &&
+	     (utf8[1] & 0xc0) == 0x80 &&
+	     (utf8[2] & 0xc0) == 0x80 &&
+	     (utf8[3] & 0xc0) == 0x80 &&
+	     (utf8[4] & 0xc0) == 0x80 &&
+	     (utf8[5] & 0xc0) == 0x80) {
+      *ucs4 =
+	((utf8[0] & 0x01L) << 30) |
+	((utf8[1] & 0x3fL) << 24) |
+	((utf8[2] & 0x3fL) << 18) |
+	((utf8[3] & 0x3fL) << 12) |
+	((utf8[4] & 0x3fL) <<  6) |
+	((utf8[5] & 0x3fL) <<  0);
+      if (*ucs4 >= 0x04000000L)
+	return utf8 - start + 6;
+    }
+
+    ++utf8;
+  }
+}
+
+/*
+ * NAME:	utf8->encodechar()
+ * DESCRIPTION:	encode a single ucs4 char into a series of up to 6 utf8 chars
+ */
+id3_length_t id3_utf8_encodechar(id3_utf8_t *utf8, id3_ucs4_t ucs4)
+{
+  if (ucs4 <= 0x0000007fL) {
+    utf8[0] = ucs4;
+
+    return 1;
+  }
+  else if (ucs4 <= 0x000007ffL) {
+    utf8[0] = 0xc0 | ((ucs4 >>  6) & 0x1f);
+    utf8[1] = 0x80 | ((ucs4 >>  0) & 0x3f);
+
+    return 2;
+  }
+  else if (ucs4 <= 0x0000ffffL) {
+    utf8[0] = 0xe0 | ((ucs4 >> 12) & 0x0f);
+    utf8[1] = 0x80 | ((ucs4 >>  6) & 0x3f);
+    utf8[2] = 0x80 | ((ucs4 >>  0) & 0x3f);
+
+    return 3;
+  }
+  else if (ucs4 <= 0x001fffffL) {
+    utf8[0] = 0xf0 | ((ucs4 >> 18) & 0x07);
+    utf8[1] = 0x80 | ((ucs4 >> 12) & 0x3f);
+    utf8[2] = 0x80 | ((ucs4 >>  6) & 0x3f);
+    utf8[3] = 0x80 | ((ucs4 >>  0) & 0x3f);
+
+    return 4;
+  }
+  else if (ucs4 <= 0x03ffffffL) {
+    utf8[0] = 0xf8 | ((ucs4 >> 24) & 0x03);
+    utf8[1] = 0x80 | ((ucs4 >> 18) & 0x3f);
+    utf8[2] = 0x80 | ((ucs4 >> 12) & 0x3f);
+    utf8[3] = 0x80 | ((ucs4 >>  6) & 0x3f);
+    utf8[4] = 0x80 | ((ucs4 >>  0) & 0x3f);
+
+    return 5;
+  }
+  else if (ucs4 <= 0x7fffffffL) {
+    utf8[0] = 0xfc | ((ucs4 >> 30) & 0x01);
+    utf8[1] = 0x80 | ((ucs4 >> 24) & 0x3f);
+    utf8[2] = 0x80 | ((ucs4 >> 18) & 0x3f);
+    utf8[3] = 0x80 | ((ucs4 >> 12) & 0x3f);
+    utf8[4] = 0x80 | ((ucs4 >>  6) & 0x3f);
+    utf8[5] = 0x80 | ((ucs4 >>  0) & 0x3f);
+
+    return 6;
+  }
+
+  /* default */
+
+  return id3_utf8_encodechar(utf8, ID3_UCS4_REPLACEMENTCHAR);
+}
+
+/*
+ * NAME:	utf8->decode()
+ * DESCRIPTION:	decode a complete utf8 string into a ucs4 string
+ */
+void id3_utf8_decode(id3_utf8_t const *utf8, id3_ucs4_t *ucs4)
+{
+  do
+    utf8 += id3_utf8_decodechar(utf8, ucs4);
+  while (*ucs4++);
+}
+
+/*
+ * NAME:	utf8->encode()
+ * DESCRIPTION:	encode a complete ucs4 string into a utf8 string
+ */
+void id3_utf8_encode(id3_utf8_t *utf8, id3_ucs4_t const *ucs4)
+{
+  do
+    utf8 += id3_utf8_encodechar(utf8, *ucs4);
+  while (*ucs4++);
+}
+
+/*
+ * NAME:	utf8->put()
+ * DESCRIPTION:	serialize a single utf8 character
+ */
+id3_length_t id3_utf8_put(id3_byte_t **ptr, id3_utf8_t utf8)
+{
+  if (ptr)
+    *(*ptr)++ = utf8;
+
+  return 1;
+}
+
+/*
+ * NAME:	utf8->get()
+ * DESCRIPTION:	deserialize a single utf8 character
+ */
+id3_utf8_t id3_utf8_get(id3_byte_t const **ptr)
+{
+  return *(*ptr)++;
+}
+
+/*
+ * NAME:	utf8->serialize()
+ * DESCRIPTION:	serialize a ucs4 string using utf8 encoding
+ */
+id3_length_t id3_utf8_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4,
+				int terminate)
+{
+  id3_length_t size = 0;
+  id3_utf8_t utf8[6], *out;
+
+  while (*ucs4) {
+    switch (id3_utf8_encodechar(out = utf8, *ucs4++)) {
+    case 6: size += id3_utf8_put(ptr, *out++);
+    case 5: size += id3_utf8_put(ptr, *out++);
+    case 4: size += id3_utf8_put(ptr, *out++);
+    case 3: size += id3_utf8_put(ptr, *out++);
+    case 2: size += id3_utf8_put(ptr, *out++);
+    case 1: size += id3_utf8_put(ptr, *out++);
+    case 0: break;
+    }
+  }
+
+  if (terminate)
+    size += id3_utf8_put(ptr, 0);
+
+  return size;
+}
+
+/*
+ * NAME:	utf8->deserialize()
+ * DESCRIPTION:	deserialize a ucs4 string using utf8 encoding
+ */
+id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **ptr, id3_length_t length)
+{
+  id3_byte_t const *end;
+  id3_utf8_t *utf8ptr, *utf8;
+  id3_ucs4_t *ucs4;
+
+  end = *ptr + length;
+
+  utf8 = malloc((length + 1) * sizeof(*utf8));
+  if (utf8 == 0)
+    return 0;
+
+  utf8ptr = utf8;
+  while (end - *ptr > 0 && (*utf8ptr = id3_utf8_get(ptr)))
+    ++utf8ptr;
+
+  *utf8ptr = 0;
+
+  ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4));
+  if (ucs4)
+    id3_utf8_decode(utf8, ucs4);
+
+  free(utf8);
+
+  return ucs4;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/utf8.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,42 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: utf8.h,v 1.7 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_UTF8_H
+# define LIBID3TAG_UTF8_H
+
+# include "id3tag.h"
+
+id3_length_t id3_utf8_length(id3_utf8_t const *);
+id3_length_t id3_utf8_size(id3_utf8_t const *);
+
+id3_length_t id3_utf8_decodechar(id3_utf8_t const *, id3_ucs4_t *);
+id3_length_t id3_utf8_encodechar(id3_utf8_t *, id3_ucs4_t);
+
+void id3_utf8_decode(id3_utf8_t const *, id3_ucs4_t *);
+void id3_utf8_encode(id3_utf8_t *, id3_ucs4_t const *);
+
+id3_length_t id3_utf8_put(id3_byte_t **, id3_utf8_t);
+id3_utf8_t id3_utf8_get(id3_byte_t const **);
+
+id3_length_t id3_utf8_serialize(id3_byte_t **, id3_ucs4_t const *, int);
+id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **, id3_length_t);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/util.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,147 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: util.c,v 1.9 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include <stdlib.h>
+# include <zlib.h>
+
+# include "id3tag.h"
+# include "util.h"
+
+/*
+ * NAME:	util->unsynchronise()
+ * DESCRIPTION:	perform (in-place) unsynchronisation
+ */
+id3_length_t id3_util_unsynchronise(id3_byte_t *data, id3_length_t length)
+{
+  id3_length_t bytes = 0, count;
+  id3_byte_t *end = data + length;
+  id3_byte_t const *ptr;
+
+  if (length == 0)
+    return 0;
+
+  for (ptr = data; ptr < end - 1; ++ptr) {
+    if (ptr[0] == 0xff && (ptr[1] == 0x00 || (ptr[1] & 0xe0) == 0xe0))
+      ++bytes;
+  }
+
+  if (bytes) {
+    ptr  = end;
+    end += bytes;
+
+    *--end = *--ptr;
+
+    for (count = bytes; count; *--end = *--ptr) {
+      if (ptr[-1] == 0xff && (ptr[0] == 0x00 || (ptr[0] & 0xe0) == 0xe0)) {
+	*--end = 0x00;
+	--count;
+      }
+    }
+  }
+
+  return length + bytes;
+}
+
+/*
+ * NAME:	util->deunsynchronise()
+ * DESCRIPTION:	undo unsynchronisation (in-place)
+ */
+id3_length_t id3_util_deunsynchronise(id3_byte_t *data, id3_length_t length)
+{
+  id3_byte_t const *old, *end = data + length;
+  id3_byte_t *new;
+
+  if (length == 0)
+    return 0;
+
+  for (old = new = data; old < end - 1; ++old) {
+    *new++ = *old;
+    if (old[0] == 0xff && old[1] == 0x00)
+      ++old;
+  }
+
+  *new++ = *old;
+
+  return new - data;
+}
+
+/*
+ * NAME:	util->compress()
+ * DESCRIPTION:	perform zlib deflate method compression
+ */
+id3_byte_t *id3_util_compress(id3_byte_t const *data, id3_length_t length,
+			      id3_length_t *newlength)
+{
+  id3_byte_t *compressed;
+
+  *newlength  = length + 12;
+  *newlength += *newlength / 1000;
+
+  compressed = malloc(*newlength);
+  if (compressed) {
+    if (compress2(compressed, newlength, data, length,
+		  Z_BEST_COMPRESSION) != Z_OK ||
+	*newlength >= length) {
+      free(compressed);
+      compressed = 0;
+    }
+    else {
+      id3_byte_t *resized;
+
+      resized = realloc(compressed, *newlength ? *newlength : 1);
+      if (resized)
+	compressed = resized;
+    }
+  }
+
+  return compressed;
+}
+
+/*
+ * NAME:	util->decompress()
+ * DESCRIPTION:	undo zlib deflate method compression
+ */
+id3_byte_t *id3_util_decompress(id3_byte_t const *data, id3_length_t length,
+				id3_length_t newlength)
+{
+  id3_byte_t *decompressed;
+
+  decompressed = malloc(newlength ? newlength : 1);
+  if (decompressed) {
+    id3_length_t size;
+
+    size = newlength;
+
+    if (uncompress(decompressed, &size, data, length) != Z_OK ||
+	size != newlength) {
+      free(decompressed);
+      decompressed = 0;
+    }
+  }
+
+  return decompressed;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/util.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,35 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: util.h,v 1.6 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_UTIL_H
+# define LIBID3TAG_UTIL_H
+
+# include "id3tag.h"
+
+id3_length_t id3_util_unsynchronise(id3_byte_t *, id3_length_t);
+id3_length_t id3_util_deunsynchronise(id3_byte_t *, id3_length_t);
+
+id3_byte_t *id3_util_compress(id3_byte_t const *, id3_length_t,
+			      id3_length_t *);
+id3_byte_t *id3_util_decompress(id3_byte_t const *, id3_length_t,
+				id3_length_t);
+
+# endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/version.c	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,45 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: version.c,v 1.7 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "global.h"
+
+# include "id3tag.h"
+# include "version.h"
+
+char const id3_version[]   = "ID3 Tag Library " ID3_VERSION;
+char const id3_copyright[] = "Copyright (C) " ID3_PUBLISHYEAR " " ID3_AUTHOR;
+char const id3_author[]    = ID3_AUTHOR " <" ID3_EMAIL ">";
+
+char const id3_build[] = ""
+# if defined(DEBUG)
+  "DEBUG "
+# elif defined(NDEBUG)
+  "NDEBUG "
+# endif
+
+# if defined(EXPERIMENTAL)
+  "EXPERIMENTAL "
+# endif
+;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libid3tag/version.h	Sun Feb 11 05:19:07 2007 -0800
@@ -0,0 +1,25 @@
+/*
+ * libid3tag - ID3 tag manipulation library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * 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
+ *
+ * $Id: version.h,v 1.7 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBID3TAG_VERSION_H
+# define LIBID3TAG_VERSION_H
+
+# endif