diff -purN old/alac_decoder/demux.c alac_decoder/demux.c
--- old/alac_decoder/demux.c	2005-03-05 05:21:42.000000000 -0800
+++ alac_decoder/demux.c	2005-07-07 21:31:17.000000000 -0700
@@ -37,11 +37,15 @@
 
 #include "stream.h"
 #include "demux.h"
+#include "metadata.h"
+
+#define CSYM '\xa9'
 
 typedef struct
 {
     stream_t *stream;
     demux_res_t *res;
+    metadata_t *metadata;
 } qtmovie_t;
 
 
@@ -511,13 +515,261 @@ static void read_chunk_mvhd(qtmovie_t *q
     stream_skip(qtmovie->stream, size_remaining);
 }
 
+/* These two functions do not expect any children. */
+static char* read_chunk_data_str (qtmovie_t *qtmovie, size_t chunk_len)
+{
+    size_t data_len = stream_read_uint32(qtmovie->stream);
+    char *buf, *ptr;
+    fourcc_t test;
+
+    if (data_len <= 1 || data_len > chunk_len)
+    {
+        fprintf(stderr, "strange size of data node\n");
+        return NULL;
+    }
+
+    test = stream_read_uint32(qtmovie->stream);
+
+    if (test != MAKEFOURCC('d','a','t','a'))
+    {
+        fprintf(stderr, "(ilst) this is NOT a data node, but a %c%c%c%c one\n",
+            SPLITFOURCC(test));
+        return NULL;
+    }
+
+    data_len -= 8;
+
+    /* XXX skip the language codes? */
+    stream_skip(qtmovie->stream, 8);
+
+    data_len -= 8;
+
+    buf = malloc(data_len + 1);
+
+    stream_read(qtmovie->stream, data_len, (void*)buf);
+
+    buf[data_len] = '\0';
+    
+    /* process \rs */
+    for (ptr = buf; *ptr != '\0'; ptr++)
+    {
+        if (*ptr == '\r')
+            *ptr = '\n';
+    }
+
+    return buf;
+}
+
+static uint16_t read_chunk_data_trackinfo (qtmovie_t *qtmovie, size_t chunk_len)
+{
+    size_t size_remaining = chunk_len - 8;
+    size_t data_len = stream_read_uint32(qtmovie->stream);
+    fourcc_t test;
+    uint16_t ret;
+
+    if (((data_len - 4) < 16) || data_len < size_remaining)
+    {
+        fprintf(stderr, "strange size for data node\n");
+        return 0;
+    }
+
+    test = stream_read_uint32(qtmovie->stream);
+
+    if (test != MAKEFOURCC('d','a','t','a'))
+    {
+        fprintf(stderr, "(ilst) this is NOT a data node, but a %c%c%c%c one\n",
+            SPLITFOURCC(test));
+        return 0;
+    }
+
+    stream_skip(qtmovie->stream, 10); /* flags + reserved + pad */
+    ret = stream_read_uint16(qtmovie->stream);
+	size_remaining -= 12;
+    stream_skip(qtmovie->stream, size_remaining - 8); /* total tracks + pad*/
+
+    return ret;
+}
+
+static uint16_t read_chunk_data_uint16 (qtmovie_t *qtmovie, size_t chunk_len)
+{
+    size_t data_len = stream_read_uint32(qtmovie->stream);
+    fourcc_t test;
+    uint16_t ret;
+
+    if ((data_len - 8) != 10 || data_len > chunk_len)
+    {
+        fprintf(stderr, "strange size of uint16 data node\n");
+        return 0;
+    }
+
+    test = stream_read_uint32(qtmovie->stream);
+
+    if (test != MAKEFOURCC('d','a','t','a'))
+    {
+        fprintf(stderr, "(ilst) this is NOT a data node, but a %c%c%c%c one\n",
+            SPLITFOURCC(test));
+        return 0;
+    }
+
+    data_len -= 8;
+    
+    stream_skip(qtmovie->stream, 8); /* flags + reserved + pad */
+    ret = stream_read_uint16(qtmovie->stream);
+
+    return ret;
+}
+
+/* 'ilst' contains the ACTUAL tag info */
+static void read_chunk_ilst(qtmovie_t *qtmovie, size_t chunk_len)
+{
+    size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+
+    while (size_remaining)
+    {
+        size_t sub_chunk_len;
+        fourcc_t sub_chunk_id;
+
+        sub_chunk_len = stream_read_uint32(qtmovie->stream);
+        if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
+        {
+            fprintf(stderr, "strange size for chunk inside ilst\n");
+            return;
+        }
+
+        sub_chunk_id = stream_read_uint32(qtmovie->stream);
+
+        switch (sub_chunk_id)
+        {
+            case MAKEFOURCC(CSYM, 'n', 'a', 'm'):
+                qtmovie->metadata->track_name = read_chunk_data_str(qtmovie, sub_chunk_len);
+                break;
+            case MAKEFOURCC(CSYM, 'A', 'R', 'T'):
+                qtmovie->metadata->track_artist = read_chunk_data_str(qtmovie, sub_chunk_len);
+                break;
+            case MAKEFOURCC(CSYM, 'a', 'l', 'b'):
+                qtmovie->metadata->track_album = read_chunk_data_str(qtmovie, sub_chunk_len);
+                break;
+            case MAKEFOURCC(CSYM, 'c', 'm', 't'):
+                qtmovie->metadata->track_comment = read_chunk_data_str(qtmovie, sub_chunk_len);
+                break;
+            case MAKEFOURCC('t', 'r', 'k', 'n'):
+                qtmovie->metadata->track_number = read_chunk_data_trackinfo(qtmovie, sub_chunk_len);
+                break;
+            case MAKEFOURCC(CSYM, 'g', 'e', 'n'):
+                qtmovie->metadata->track_genre_str = read_chunk_data_str(qtmovie, sub_chunk_len);
+                break;
+            case MAKEFOURCC('g', 'n', 'r', 'e'):
+                qtmovie->metadata->track_genre = read_chunk_data_uint16(qtmovie, sub_chunk_len);
+                break;
+            case MAKEFOURCC('t', 'm', 'p', 'o'):
+                qtmovie->metadata->track_tempo = read_chunk_data_uint16(qtmovie, sub_chunk_len);
+                break;
+            case MAKEFOURCC(CSYM, 't', 'o', 'o'):
+                qtmovie->metadata->track_tool = read_chunk_data_str(qtmovie, sub_chunk_len);
+                break;
+           case MAKEFOURCC(CSYM, 'd', 'a', 'y'):
+               qtmovie->metadata->track_year = read_chunk_data_str(qtmovie, sub_chunk_len);
+               break;
+           case MAKEFOURCC('d','i','s','k'):
+               qtmovie->metadata->track_disk = read_chunk_data_trackinfo(qtmovie, sub_chunk_len);
+               break;
+           case MAKEFOURCC(CSYM, 'w', 'r', 't'):
+               qtmovie->metadata->track_composer = read_chunk_data_str(qtmovie, sub_chunk_len);
+               break;
+            /* silent ignore*/
+            case MAKEFOURCC('c', 'p', 'i', 'l'):
+                stream_skip(qtmovie->stream, sub_chunk_len - 8);
+                break;
+            case MAKEFOURCC('-', '-', '-', '-'):
+                stream_skip(qtmovie->stream, sub_chunk_len - 8);
+                return;
+            default:
+                fprintf(stderr, "(ilst) unknown chunk id: %c%c%c%c\n",
+                    SPLITFOURCC(sub_chunk_id));
+                stream_skip(qtmovie->stream, sub_chunk_len - 8);
+        }
+        
+        size_remaining -= sub_chunk_len;
+    }
+}
+
+/* 'meta' metadata, contains tag info */
+static void read_chunk_meta(qtmovie_t *qtmovie, size_t chunk_len)
+{
+    size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+
+    /* ??? */
+    stream_skip(qtmovie->stream, 4);
+    size_remaining -= 4;
+
+    while (size_remaining)
+    {
+        fourcc_t sub_chunk_id;
+        size_t sub_chunk_len;
+        
+        sub_chunk_len = stream_read_uint32(qtmovie->stream);
+        if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
+        {
+            fprintf(stderr, "strange size for chunk inside meta\n");
+            return;
+        }
+        
+        sub_chunk_id = stream_read_uint32(qtmovie->stream);
+
+        switch (sub_chunk_id)
+        {
+            case MAKEFOURCC('h', 'd', 'l', 'r'):
+                /* don't understand why this is here at all */
+                stream_skip(qtmovie->stream, sub_chunk_len - 8);
+                break;
+            case MAKEFOURCC('i', 'l', 's', 't'):
+                read_chunk_ilst(qtmovie, chunk_len);
+                break;
+            case MAKEFOURCC('f', 'r', 'e', 'e'): /* considered done */
+            case MAKEFOURCC('-', '-', '-', '-'):
+                stream_skip(qtmovie->stream, sub_chunk_len - 8);
+                return;
+            default:
+                fprintf(stderr, "(meta) unknown chunk id: %c%c%c%c\n",
+                    SPLITFOURCC(sub_chunk_id));
+                stream_skip(qtmovie->stream, sub_chunk_len - 8);
+        }
+        size_remaining -= sub_chunk_len;
+    }
+}
+
 /* 'udta' user data.. contains tag info */
 static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
 {
-    /* don't need anything from here atm, skip */
     size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
 
-    stream_skip(qtmovie->stream, size_remaining);
+    while (size_remaining)
+    {
+        size_t sub_chunk_len;
+        fourcc_t sub_chunk_id;
+
+        sub_chunk_len = stream_read_uint32(qtmovie->stream);
+        if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
+        {
+            fprintf(stderr, "strange size for chunk inside udta\n");
+            return;
+        }
+
+        sub_chunk_id = stream_read_uint32(qtmovie->stream);
+
+        switch(sub_chunk_id)
+        {
+            case MAKEFOURCC('m','e','t','a'):
+                read_chunk_meta(qtmovie, sub_chunk_len);
+                break;
+            default:
+                fprintf(stderr, "(udta) unknown chunk id: %c%c%c%c\n",
+                     SPLITFOURCC(sub_chunk_id));
+                return;
+        }
+
+        size_remaining -= sub_chunk_len;
+    }
 }
 
 /* 'moov' movie atom - contains other atoms */
@@ -572,7 +824,7 @@ static void read_chunk_mdat(qtmovie_t *q
 #endif
 }
 
-int qtmovie_read(stream_t *file, demux_res_t *demux_res)
+int qtmovie_read(stream_t *file, demux_res_t *demux_res, metadata_t *metadata)
 {
     qtmovie_t *qtmovie;
 
@@ -580,7 +832,7 @@ int qtmovie_read(stream_t *file, demux_r
 
     /* construct the stream */
     qtmovie->stream = file;
-
+    qtmovie->metadata = metadata;
     qtmovie->res = demux_res;
 
     /* read the chunks */
diff -purN old/alac_decoder/demux.h alac_decoder/demux.h
--- old/alac_decoder/demux.h	2005-03-04 23:31:17.000000000 -0800
+++ alac_decoder/demux.h	2005-07-07 21:27:53.000000000 -0700
@@ -3,6 +3,7 @@
 
 #include <stdint.h>
 #include "stream.h"
+#include "metadata.h"
 
 typedef uint32_t fourcc_t;
 
@@ -32,7 +33,7 @@ typedef struct
 #endif
 } demux_res_t;
 
-int qtmovie_read(stream_t *stream, demux_res_t *demux_res);
+int qtmovie_read(stream_t *stream, demux_res_t *demux_res, metadata_t *metadata);
 
 #ifndef MAKEFOURCC
 #define MAKEFOURCC(ch0, ch1, ch2, ch3) ( \
@@ -42,7 +43,7 @@ int qtmovie_read(stream_t *stream, demux
     ( (int32_t)(char)(ch3) ) )
 #endif
 
-#ifndef SLPITFOURCC
+#ifndef SPLITFOURCC
 /* splits it into ch0, ch1, ch2, ch3 - use for printf's */
 #define SPLITFOURCC(code) \
     (char)((int32_t)code >> 24), \
diff -purN old/alac_decoder/main.c alac_decoder/main.c
--- old/alac_decoder/main.c	2005-03-05 05:30:51.000000000 -0800
+++ alac_decoder/main.c	2005-07-07 21:33:27.000000000 -0700
@@ -57,6 +57,7 @@ static int output_opened = 0;
 
 static int write_wav_format = 1;
 static int verbose = 0;
+static int info = 0;
 
 static int get_sample_info(demux_res_t *demux_res, uint32_t samplenum,
                            uint32_t *sample_duration,
@@ -165,6 +166,7 @@ static void usage()
                     "  -f output.wav     outputs the decompressed data to the\n"
                     "                    specified file, in WAV format. Default\n"
                     "                    is stdout.\n"
+                    "  -i                dump metadata to stdout and exit.\n"
                     "  -r                write output as raw PCM data. Default\n"
                     "                    is in WAV format.\n"
                     "  -v                verbose output.\n"
@@ -201,6 +203,10 @@ static void setup_environment(int argc, 
         {
             verbose = 1;
         }
+        else if (strcmp(argv[argc-i], "-i") == 0) /* info */
+        {
+            info = 1;
+        }
         else if (strcmp(argv[argc-i], "--") == 0) /* filename can begin with - */
         {
             /* must be 2nd last arg */
@@ -273,8 +279,11 @@ void set_endian()
 int main(int argc, char **argv)
 {
     demux_res_t demux_res;
+    metadata_t metadata;
     unsigned int output_size, i;
 
+    memset(&metadata, 0, sizeof(metadata_t));
+
     set_endian();
 
     setup_environment(argc, argv);
@@ -288,11 +297,45 @@ int main(int argc, char **argv)
 
     /* if qtmovie_read returns successfully, the stream is up to
      * the movie data, which can be used directly by the decoder */
-    if (!qtmovie_read(input_stream, &demux_res))
+    if (!qtmovie_read(input_stream, &demux_res, &metadata))
     {
         fprintf(stderr, "failed to load the QuickTime movie headers\n");
         return 0;
     }
+    
+    if (info)
+    {
+        printf("Available track information:\n\n");
+
+        if (metadata.track_name)
+            printf("title: %s\n", metadata.track_name);
+        if (metadata.track_artist)
+            printf("artist: %s\n", metadata.track_artist);
+        if (metadata.track_composer)
+            printf("composer: %s\n", metadata.track_composer);
+        if (metadata.track_album)
+            printf("album: %s\n", metadata.track_album);
+        if (metadata.track_disk)
+            printf("disk: %d\n", metadata.track_disk);
+        if (metadata.track_year)
+            printf("date: %s\n", metadata.track_year);
+        if (metadata.track_tool)
+            printf("tool: %s\n", metadata.track_tool);
+        if (metadata.track_number > 0)
+            printf("tracknumber: %d\n", metadata.track_number);
+        if (metadata.track_comment)
+            printf("comment: %s\n", metadata.track_comment);
+
+        if (metadata.track_genre_str)
+            printf("genre: %s\n", metadata.track_genre_str);
+        else if (metadata.track_genre > 0)
+            printf("genre: %s\n", get_genre(metadata.track_genre - 1));
+
+        if (metadata.track_tempo > 0)
+            printf("tempo: %d\n", metadata.track_tempo);
+
+        return 0;
+    }
 
     /* initialise the sound converter */
     init_sound_converter(&demux_res);
diff -purN old/alac_decoder/Makefile alac_decoder/Makefile
--- old/alac_decoder/Makefile	2005-03-05 05:37:50.000000000 -0800
+++ alac_decoder/Makefile	2005-07-07 21:27:53.000000000 -0700
@@ -6,7 +6,8 @@ C_SOURCES=alac.c \
           demux.c \
           main.c \
           stream.c \
-          wavwriter.c
+          wavwriter.c \
+          metadata.c
 
 OBJECTS=$(C_SOURCES:.c=.o)
 
diff -purN old/alac_decoder/metadata.c alac_decoder/metadata.c
--- old/alac_decoder/metadata.c	1969-12-31 16:00:00.000000000 -0800
+++ alac_decoder/metadata.c	2005-07-07 21:27:53.000000000 -0700
@@ -0,0 +1,180 @@
+/*
+ * ALAC (Apple Lossless Audio Codec) decoder
+ * Copyright (c) 2005 David Hammerton
+ * All rights reserved.
+ *
+ * This file, for now, contains a way to map genre IDs (ID3v2) to strings.
+ *
+ * http://crazney.net/programs/itunes/alac.html
+ * 
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" }, WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "metadata.h"
+#include <stdlib.h>
+
+/* Mostly ripped off from faad2/common/faad/id3v2tag.c */
+
+genre id3_genres[]=
+{
+    { 123,    "Acapella" },
+    { 34,     "Acid" },
+    { 74,     "Acid Jazz" },
+    { 73,     "Acid Punk" },
+    { 99,     "Acoustic" },
+    { 20,     "Alternative" },
+    { 40,     "AlternRock" },
+    { 26,     "Ambient" },
+    { 90,     "Avantgarde" },
+    { 116,    "Ballad" },
+    { 41,     "Bass" },
+    { 85,     "Bebob" },
+    { 96,     "Big Band" },
+    { 89,     "Bluegrass" },
+    { 0,      "Blues" },
+    { 107,    "Booty Bass" },
+    { 65,     "Cabaret" },
+    { 88,     "Celtic" },
+    { 104,    "Chamber Music" },
+    { 102,    "Chanson" },
+    { 97,     "Chorus" },
+    { 61,     "Christian Rap" },
+    { 1,      "Classic Rock" },
+    { 32,     "Classical" },
+    { 112,    "Club" },
+    { 57,     "Comedy" },
+    { 2,      "Country" },
+    { 58,     "Cult" },
+    { 3,      "Dance" },
+    { 125,    "Dance Hall" },
+    { 50,     "Darkwave" },
+    { 254,    "Data" },
+    { 22,     "Death Metal" },
+    { 4,      "Disco" },
+    { 55,     "Dream" },
+    { 122,    "Drum Solo" },
+    { 120,    "Duet" },
+    { 98,     "Easy Listening" },
+    { 52,     "Electronic" },
+    { 48,     "Ethnic" },
+    { 124,    "Euro-House" },
+    { 25,     "Euro-Techno" },
+    { 54,     "Eurodance" },
+    { 84,     "Fast Fusion" },
+    { 80,     "Folk" },
+    { 81,     "Folk-Rock" },
+    { 115,    "Folklore" },
+    { 119,    "Freestyle" },
+    { 5,      "Funk" },
+    { 30,     "Fusion" },
+    { 36,     "Game" },
+    { 59,     "Gangsta" },
+    { 38,     "Gospel" },
+    { 49,     "Gothic" },
+    { 91,     "Gothic Rock" },
+    { 6,      "Grunge" },
+    { 79,     "Hard Rock" },
+    { 7,      "Hip-Hop" },
+    { 35,     "House" },
+    { 100,    "Humour" },
+    { 19,     "Industrial" },
+    { 33,     "Instrumental" },
+    { 46,     "Instrumental Pop" },
+    { 47,     "Instrumental Rock" },
+    { 8,      "Jazz" },
+    { 29,     "Jazz+Funk" },
+    { 63,     "Jungle" },
+    { 86,     "Latin" },
+    { 71,     "Lo-Fi" },
+    { 45,     "Meditative" },
+    { 9,      "Metal" },
+    { 77,     "Musical" },
+    { 82,     "National Folk" },
+    { 64,     "Native American" },
+    { 10,     "New Age" },
+    { 66,     "New Wave" },
+    { 39,     "Noise" },
+    { 255,    "Not Set" },
+    { 11,     "Oldies" },
+    { 103,    "Opera" },
+    { 12,     "Other" },
+    { 75,     "Polka" },
+    { 13,     "Pop" },
+    { 62,     "Pop/Funk" },
+    { 53,     "Pop-Folk" },
+    { 109,    "Porn Groove" },
+    { 117,    "Power Ballad" },
+    { 23,     "Pranks" },
+    { 108,    "Primus" },
+    { 92,     "Progressive Rock" },
+    { 67,     "Psychadelic" },
+    { 93,     "Psychedelic Rock" },
+    { 43,     "Punk" },
+    { 121,    "Punk Rock" },
+    { 14,     "R&B" },
+    { 15,     "Rap" },
+    { 68,     "Rave" },
+    { 16,     "Reggae" },
+    { 76,     "Retro" },
+    { 87,     "Revival" },
+    { 118,    "Rhythmic Soul" },
+    { 17,     "Rock" },
+    { 78,     "Rock & Roll" },
+    { 114,    "Samba" },
+    { 110,    "Satire" },
+    { 69,     "Showtunes" },
+    { 21,     "Ska" },
+    { 111,    "Slow Jam" },
+    { 95,     "Slow Rock" },
+    { 105,    "Sonata" },
+    { 42,     "Soul" },
+    { 37,     "Sound Clip" },
+    { 24,     "Soundtrack" },
+    { 56,     "Southern Rock" },
+    { 44,     "Space" },
+    { 101,    "Speech" },
+    { 83,     "Swing" },
+    { 94,     "Symphonic Rock" },
+    { 106,    "Symphony" },
+    { 113,    "Tango" },
+    { 18,     "Techno" },
+    { 51,     "Techno-Industrial" },
+    { 60,     "Top 40" },
+    { 70,     "Trailer" },
+    { 31,     "Trance" },
+    { 72,     "Tribal" },
+    { 27,     "Trip-Hop" },
+    { 28,     "Vocal" },
+    { 0 ,     "\0" }
+};
+
+const char* get_genre (uint16_t id)
+{
+    genre* ptr = NULL;
+    
+    for (ptr = id3_genres; ptr->name != NULL; ptr++)
+    {
+        if (ptr->id == id)
+            return ptr->name;
+    }
+    return NULL;
+}
diff -purN old/alac_decoder/metadata.h alac_decoder/metadata.h
--- old/alac_decoder/metadata.h	1969-12-31 16:00:00.000000000 -0800
+++ alac_decoder/metadata.h	2005-07-07 21:32:18.000000000 -0700
@@ -0,0 +1,29 @@
+#ifndef METADATA_H
+#define METADATA_H
+
+#include <stdint.h>
+
+typedef struct {
+    char* track_name;
+    char* track_artist;
+    char* track_album;
+    char* track_comment;
+    char* track_tool;
+    char* track_year;
+    char* track_composer;
+    char* track_genre_str;
+    uint16_t track_number;
+    uint16_t track_genre;
+    uint16_t track_tempo;
+    uint16_t track_disk;
+} metadata_t;
+
+typedef struct genre_pair
+{
+    uint16_t id;
+    char name[30];
+} genre;
+
+extern const char* get_genre (uint16_t id);
+
+#endif
