more doxygen docs
diff --git a/include/FLAC++/all.h b/include/FLAC++/all.h
index 02c43b4..ab91978 100644
--- a/include/FLAC++/all.h
+++ b/include/FLAC++/all.h
@@ -24,4 +24,12 @@
 #include "decoder.h"
 #include "metadata.h"
 
+/** \defgroup flacpp FLAC C++ API
+ *
+ * The FLAC C++ API is the interface to libFLAC++, a set of classes
+ * that encapsulate the encoders, decoders, and metadata interfaces
+ * in libFLAC.
+ *
+ */
+
 #endif
diff --git a/include/FLAC++/decoder.h b/include/FLAC++/decoder.h
index de8884d..e665c0a 100644
--- a/include/FLAC++/decoder.h
+++ b/include/FLAC++/decoder.h
@@ -32,6 +32,25 @@
 // ===============================================================
 
 
+/** \file include/FLAC++/decoder.h
+ *
+ *  \brief
+ *  This file contains the classes which implement the various
+ *  decoders.
+ *
+ *  See the detailed documentation in the
+ *  \link flacpp_decoder decoder \endlink module.
+ */
+
+/** \defgroup flacpp_decoder FLAC++/decoder.h: decoder classes
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  Brief XXX.
+ *
+ * Detailed decoder XXX.
+ */
+
 namespace FLAC {
 	namespace Decoder {
 
@@ -51,6 +70,18 @@
 		//
 		// ============================================================
 
+		/** \defgroup flacpp_stream_decoder FLAC++/decoder.h: stream decoder class
+		 *  \ingroup flacpp_decoder
+		 *
+		 *  \brief
+		 *  Brief XXX.
+		 *
+		 * Detailed stream decoder XXX.
+		 * \{
+		 */
+
+		/** stream decoder XXX.
+		 */
 		class Stream {
 		public:
 			class State {
@@ -114,12 +145,27 @@
 			void operator=(const Stream &);
 		};
 
+		/* \} */
+
+
 		// ============================================================
 		//
 		//  Equivalent: FLAC__SeekableStreamDecoder
 		//
 		// ============================================================
 
+		/** \defgroup flacpp_seekable_stream_decoder FLAC++/decoder.h: seekable stream decoder class
+		 *  \ingroup flacpp_decoder
+		 *
+		 *  \brief
+		 *  Brief XXX.
+		 *
+		 * Detailed seekable stream decoder XXX.
+		 * \{
+		 */
+
+		/** seekable stream decoder XXX.
+		 */
 		class SeekableStream {
 		public:
 			class State {
@@ -192,12 +238,27 @@
 			void operator=(const SeekableStream &);
 		};
 
+		/* \} */
+
+
 		// ============================================================
 		//
 		//  Equivalent: FLAC__FileDecoder
 		//
 		// ============================================================
 
+		/** \defgroup flacpp_file_decoder FLAC++/decoder.h: file decoder class
+		 *  \ingroup flacpp_decoder
+		 *
+		 *  \brief
+		 *  Brief XXX.
+		 *
+		 * Detailed file decoder XXX.
+		 * \{
+		 */
+
+		/** file decoder XXX.
+		 */
 		class File {
 		public:
 			class State {
@@ -258,6 +319,8 @@
 			void operator=(const File &);
 		};
 
+		/* \} */
+
 	};
 };
 
diff --git a/include/FLAC++/encoder.h b/include/FLAC++/encoder.h
index dca7d4c..7166e28 100644
--- a/include/FLAC++/encoder.h
+++ b/include/FLAC++/encoder.h
@@ -30,6 +30,25 @@
 // ===============================================================
 
 
+/** \file include/FLAC++/encoder.h
+ *
+ *  \brief
+ *  This module contains the classes which implement the various
+ *  encoders.
+ *
+ *  See the detailed documentation in the
+ *  \link flacpp_encoder encoder \endlink module.
+ */
+
+/** \defgroup flacpp_encoder FLAC++/encoder.h: encoder classes
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  Brief XXX.
+ *
+ * Detailed encoder XXX.
+ */
+
 namespace FLAC {
 	namespace Encoder {
 
@@ -47,6 +66,18 @@
 		//
 		// ============================================================
 
+		/** \defgroup flacpp_stream_encoder FLAC++/encoder.h: stream encoder class
+		 *  \ingroup flacpp_encoder
+		 *
+		 *  \brief
+		 *  Brief XXX.
+		 *
+		 * Detailed stream encoder XXX.
+		 * \{
+		 */
+
+		/** stream encoder XXX.
+		 */
 		class Stream {
 		public:
 			class State {
@@ -122,6 +153,8 @@
 			void operator=(const Stream &);
 		};
 
+		/* \} */
+
 	};
 };
 
diff --git a/include/FLAC++/metadata.h b/include/FLAC++/metadata.h
index d08c812..f9d7325 100644
--- a/include/FLAC++/metadata.h
+++ b/include/FLAC++/metadata.h
@@ -29,6 +29,30 @@
 //
 // ===============================================================
 
+/** \file include/FLAC++/metadata.h
+ *
+ *  \brief
+ *  This module provides classes for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  See the detailed documentation for each interface in the
+ *  \link flacpp_metadata metadata \endlink module.
+ */
+
+/** \defgroup flacpp_metadata FLAC++/metadata.h: metadata interfaces
+ *  \ingroup flacpp
+ *
+ *  \brief
+ *  This module provides classes for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  The behavior closely mimics the C layer interface; be sure to read
+ *  the detailed description of the
+ *  \link flac_metadata C metadata module \endlink.
+ */
+
 
 namespace FLAC {
 	namespace Metadata {
@@ -39,77 +63,129 @@
 		//
 		// ============================================================
 
-		class Prototype;
+		/** \defgroup flacpp_metadata_object FLAC++/metadata.h: metadata object classes
+		 *  \ingroup flacpp_metadata
+		 *
+		 * This module contains classes representing FLAC metadata
+		 * blocks in memory.
+		 *
+		 * The behavior closely mimics the C layer interface; be
+		 * sure to read the detailed description of the
+		 * \link flac_metadata_object C metadata object module \endlink.
+		 *
+		 * Any time a metadata object is constructed or assigned, you
+		 * should check is_valid() to make sure the underlying
+		 * ::FLAC__StreamMetadata object was able to be created.
+		 *
+		 * \warning
+		 * When the get_*() methods of any metadata object method
+		 * return you a const pointer, DO NOT disobey and write into it.
+		 * Always use the set_*() methods.
+		 *
+		 * \{
+		 */
 
-		Prototype *clone(const Prototype *);
-
-		// NOTE: When the get_*() methods return you a const pointer,
-		// DO NOT disobey and write into it.  Always use the set_*()
-		// methods.
-
-		//!
-		//! \class Prototype metadata.h FLAC++/metadata.h
-		//! \brief Base class for all metadata block types.
-		//!
+		/** Base class for all metadata block types.
+		 */
 		class Prototype {
 		protected:
-			//!
-			//! Constructs a copy of the given object.  This form
-			//! always performs a deep copy.
-			//!
-			Prototype(const Prototype &object);
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			Prototype(const Prototype &);
+			Prototype(const ::FLAC__StreamMetadata &);
+			Prototype(const ::FLAC__StreamMetadata *);
+			//@}
 
-			//!
-			//! Constructs a copy of the given object.  This form
-			//! always performs a deep copy.
-			//!
-			Prototype(const ::FLAC__StreamMetadata &object);
-
-			//!
-			//! Constructs a copy of the given object.  This form
-			//! always performs a deep copy.
-			//!
-			Prototype(const ::FLAC__StreamMetadata *object);
-
-			//!
-			//! Constructs an object with copy control.  When 'copy'
-			//! is true, behaves identically to
-			//! FLAC::Metadata::Prototype::Prototype(const ::FLAC__StreamMetadata *object).
-			//! When 'copy' is false, the instance takes ownership of
-			//! the pointer and the ::FLAC__StreamMetadata object will
-			//! be freed by the destructor.
-			//!
+			/** Constructs an object with copy control.  When \a copy
+			 *  is \c true, behaves identically to
+			 *  FLAC::Metadata::Prototype::Prototype(const ::FLAC__StreamMetadata *object).
+			 *  When \a copy is \c false, the instance takes ownership of
+			 *  the pointer and the ::FLAC__StreamMetadata object will
+			 *  be freed by the destructor.
+			 *
+			 *  \assert
+			 *    \code object != NULL \endcode
+			 */
 			Prototype(::FLAC__StreamMetadata *object, bool copy);
 
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
 			void operator=(const Prototype &);
-			void operator=(const ::FLAC__StreamMetadata &); // this form always copies
-			void operator=(const ::FLAC__StreamMetadata *); // this form always copies
+			void operator=(const ::FLAC__StreamMetadata &);
+			void operator=(const ::FLAC__StreamMetadata *);
+			//@}
 
+			/** Deletes the underlying ::FLAC__StreamMetadata object.
+			 */
 			virtual void clear();
 
 			::FLAC__StreamMetadata *object_;
 		public:
+			/** Deletes the underlying ::FLAC__StreamMetadata object.
+			 */
 			virtual ~Prototype();
 
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
 			inline bool operator==(const Prototype &) const;
 			inline bool operator==(const ::FLAC__StreamMetadata &) const;
 			inline bool operator==(const ::FLAC__StreamMetadata *) const;
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
 			inline bool operator!=(const Prototype &) const;
 			inline bool operator!=(const ::FLAC__StreamMetadata &) const;
 			inline bool operator!=(const ::FLAC__StreamMetadata *) const;
+			//@}
 
 			friend class SimpleIterator;
 			friend class Iterator;
 
+			/** Returns \c true if the object was correctly constructed
+			 *  (i.e. the underlying ::FLAC__StreamMetadata object was
+			 *  properly allocated), else \c false.
+			 */
 			inline bool is_valid() const;
 
+			/** Returns \c true if this block is the last block in a
+			 *  stream, else \c false.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
 			bool get_is_last() const;
-			FLAC__MetadataType get_type() const;
-			unsigned get_length() const; // NOTE: does not include the header, per spec
 
+			/** Returns the type of the block.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
+			::FLAC__MetadataType get_type() const;
+
+			/** Returns the stream length of the metadata block.
+			 *
+			 * \note
+			 *   The length does not include the metadata block header,
+			 *   per spec.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
+			unsigned get_length() const;
+
+			/** Sets the "is_last" flag for the block.  When using the iterators
+			 *  it is not necessary to set this flag; they will do it for you.
+			 *
+			 * \assert
+			 *   \code is_valid() \endcode
+			 */
 			void set_is_last(bool);
 		private:
-			Prototype(); // Private and undefined so you can't use it
+			/** Private and undefined so you can't use it. */
+			Prototype();
 
 			// These are used only by Iterator
 			bool is_reference_;
@@ -137,26 +213,55 @@
 		inline bool Prototype::is_valid() const
 		{ return 0 != object_; }
 
+		/** Create a deep copy of an object and return it. */
+		Prototype *clone(const Prototype *);
 
+
+		/** STREAMINFO metadata block.
+		 */
 		class StreamInfo : public Prototype {
 		public:
 			StreamInfo();
+
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
 			inline StreamInfo(const StreamInfo &object): Prototype(object) { }
 			inline StreamInfo(const ::FLAC__StreamMetadata &object): Prototype(object) { }
 			inline StreamInfo(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 *
+			 *  \assert
+			 *    \code object != NULL \endcode
+			 */
 			inline StreamInfo(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
 			~StreamInfo();
 
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
 			inline void operator=(const StreamInfo &object) { Prototype::operator=(object); }
 			inline void operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); }
 			inline void operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); }
+			//@}
 
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
 			inline bool operator==(const StreamInfo &object) const { return Prototype::operator==(object); }
 			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
 			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
 			inline bool operator!=(const StreamInfo &object) const { return Prototype::operator!=(object); }
 			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
 			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
 
 			unsigned get_min_blocksize() const;
 			unsigned get_max_blocksize() const;
@@ -179,6 +284,8 @@
 			void set_md5sum(const FLAC__byte value[16]);
 		};
 
+		/** PADDING block.
+		 */
 		class Padding : public Prototype {
 		public:
 			Padding();
@@ -202,6 +309,8 @@
 			void set_length(unsigned length);
 		};
 
+		/** APPLICATION block.
+		 */
 		class Application : public Prototype {
 		public:
 			Application();
@@ -230,6 +339,8 @@
 			bool set_data(FLAC__byte *data, unsigned length, bool copy);
 		};
 
+		/** SEEKTABLE block.
+		 */
 		class SeekTable : public Prototype {
 		public:
 			SeekTable();
@@ -260,8 +371,12 @@
 			bool is_legal() const;
 		};
 
+		/** VORBIS_COMMENT block.
+		 */
 		class VorbisComment : public Prototype {
 		public:
+			/** XXX class VorbisComment::Entry
+			 */
 			class Entry {
 			public:
 				Entry();
@@ -333,6 +448,8 @@
 			bool delete_comment(unsigned index);
 		};
 
+		/* \} */
+
 
 		// ============================================================
 		//
@@ -340,8 +457,21 @@
 		//
 		// ============================================================
 
+		/** \defgroup flacpp_metadata_level0 FLAC++/metadata.h: metadata level 0 interface
+		 *  \ingroup flacpp_metadata
+		 *
+		 *  \brief
+		 *  XXX
+		 *
+		 * Detailed XXX.
+		 *
+		 * \{
+		 */
+
 		bool get_streaminfo(const char *filename, StreamInfo &streaminfo);
 
+		/* \} */
+
 
 		// ============================================================
 		//
@@ -371,8 +501,23 @@
 		//
 		// ============================================================
 
+		/** \defgroup flacpp_metadata_level1 FLAC++/metadata.h: metadata level 1 interface
+		 *  \ingroup flacpp_metadata
+		 *
+		 * \brief
+		 * XXX
+		 *
+		 * Detailed XXX.
+		 *
+		 * \{
+		 */
+
+		/** XXX class SimpleIterator
+		 */
 		class SimpleIterator {
 		public:
+			/** XXX class SimpleIterator::Status
+			 */
 			class Status {
 			public:
 				inline Status(::FLAC__Metadata_SimpleIteratorStatus status): status_(status) { }
@@ -405,6 +550,8 @@
 			void clear();
 		};
 
+		/* \} */
+
 
 		// ============================================================
 		//
@@ -443,8 +590,23 @@
 		//
 		// ============================================================
 
+		/** \defgroup flacpp_metadata_level2 FLAC++/metadata.h: metadata level 2 interface
+		 *  \ingroup flacpp_metadata
+		 *
+		 * \brief
+		 * XXX
+		 *
+		 * Detailed XXX.
+		 *
+		 * \{
+		 */
+
+		/** XXX class Chain
+		 */
 		class Chain {
 		public:
+			/** XXX class Chain::Status
+			 */
 			class Status {
 			public:
 				inline Status(::FLAC__Metadata_ChainStatus status): status_(status) { }
@@ -473,6 +635,8 @@
 			virtual void clear();
 		};
 
+		/** XXX class Iterator
+		 */
 		class Iterator {
 		public:
 			Iterator();
@@ -497,7 +661,872 @@
 			virtual void clear();
 		};
 
+		/* \} */
+
 	};
 };
 
 #endif
+#if 0
+		Prototype *clone(const Prototype *object)
+		{
+			FLAC__ASSERT(0 != object);
+
+			const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
+			const Padding *padding = dynamic_cast<const Padding *>(object);
+			const Application *application = dynamic_cast<const Application *>(object);
+			const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
+			const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
+
+			if(0 != streaminfo)
+				return new StreamInfo(*streaminfo);
+			else if(0 != padding)
+				return new Padding(*padding);
+			else if(0 != application)
+				return new Application(*application);
+			else if(0 != seektable)
+				return new SeekTable(*seektable);
+			else if(0 != vorbiscomment)
+				return new VorbisComment(*vorbiscomment);
+			else {
+				FLAC__ASSERT(0);
+				return 0;
+			}
+		}
+
+		//
+		// StreamInfo
+		//
+
+		StreamInfo::StreamInfo():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false)
+		{ }
+
+		StreamInfo::~StreamInfo()
+		{ }
+
+		unsigned StreamInfo::get_min_blocksize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.min_blocksize;
+		}
+
+		unsigned StreamInfo::get_max_blocksize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.max_blocksize;
+		}
+
+		unsigned StreamInfo::get_min_framesize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.min_framesize;
+		}
+
+		unsigned StreamInfo::get_max_framesize() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.max_framesize;
+		}
+
+		unsigned StreamInfo::get_sample_rate() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.sample_rate;
+		}
+
+		unsigned StreamInfo::get_channels() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.channels;
+		}
+
+		unsigned StreamInfo::get_bits_per_sample() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.bits_per_sample;
+		}
+
+		FLAC__uint64 StreamInfo::get_total_samples() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.total_samples;
+		}
+
+		const FLAC__byte *StreamInfo::get_md5sum() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.stream_info.md5sum;
+		}
+
+		void StreamInfo::set_min_blocksize(unsigned value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
+			FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
+			object_->data.stream_info.min_blocksize = value;
+		}
+
+		void StreamInfo::set_max_blocksize(unsigned value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
+			FLAC__ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
+			object_->data.stream_info.max_blocksize = value;
+		}
+
+		void StreamInfo::set_min_framesize(unsigned value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
+			object_->data.stream_info.min_framesize = value;
+		}
+
+		void StreamInfo::set_max_framesize(unsigned value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value < (1u < FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
+			object_->data.stream_info.max_framesize = value;
+		}
+
+		void StreamInfo::set_sample_rate(unsigned value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(FLAC__format_sample_rate_is_valid(value));
+			object_->data.stream_info.sample_rate = value;
+		}
+
+		void StreamInfo::set_channels(unsigned value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value > 0);
+			FLAC__ASSERT(value <= FLAC__MAX_CHANNELS);
+			object_->data.stream_info.channels = value;
+		}
+
+		void StreamInfo::set_bits_per_sample(unsigned value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
+			FLAC__ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
+			object_->data.stream_info.bits_per_sample = value;
+		}
+
+		void StreamInfo::set_total_samples(FLAC__uint64 value)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
+			object_->data.stream_info.total_samples = value;
+		}
+
+		void StreamInfo::set_md5sum(const FLAC__byte value[16])
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != value);
+			memcpy(object_->data.stream_info.md5sum, value, 16);
+		}
+
+
+		//
+		// Padding
+		//
+
+		Padding::Padding():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false)
+		{ }
+
+		Padding::~Padding()
+		{ }
+
+		void Padding::set_length(unsigned length)
+		{
+			FLAC__ASSERT(is_valid());
+			object_->length = length;
+		}
+
+
+		//
+		// Application
+		//
+
+		Application::Application():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false)
+		{ }
+
+		Application::~Application()
+		{ }
+
+		const FLAC__byte *Application::get_id() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.application.id;
+		}
+
+		const FLAC__byte *Application::get_data() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.application.data;
+		}
+
+		void Application::set_id(const FLAC__byte value[4])
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != value);
+			memcpy(object_->data.application.id, value, 4);
+		}
+
+		bool Application::set_data(const FLAC__byte *data, unsigned length)
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_object_application_set_data(object_, (FLAC__byte*)data, length, true);
+		}
+
+		bool Application::set_data(FLAC__byte *data, unsigned length, bool copy)
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_object_application_set_data(object_, data, length, copy);
+		}
+
+
+		//
+		// SeekTable
+		//
+
+		SeekTable::SeekTable():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false)
+		{ }
+
+		SeekTable::~SeekTable()
+		{ }
+
+		unsigned SeekTable::get_num_points() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.seek_table.num_points;
+		}
+
+		::FLAC__StreamMetadata_SeekPoint SeekTable::get_point(unsigned index) const
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(index < object_->data.seek_table.num_points);
+			return object_->data.seek_table.points[index];
+		}
+
+		void SeekTable::set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(index < object_->data.seek_table.num_points);
+			::FLAC__metadata_object_seektable_set_point(object_, index, point);
+		}
+
+		bool SeekTable::insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(index <= object_->data.seek_table.num_points);
+			return (bool)::FLAC__metadata_object_seektable_insert_point(object_, index, point);
+		}
+
+		bool SeekTable::delete_point(unsigned index)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(index < object_->data.seek_table.num_points);
+			return (bool)::FLAC__metadata_object_seektable_delete_point(object_, index);
+		}
+
+		bool SeekTable::is_legal() const
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_object_seektable_is_legal(object_);
+		}
+
+
+		//
+		// VorbisComment::Entry
+		//
+
+		VorbisComment::Entry::Entry()
+		{
+			zero();
+		}
+
+		VorbisComment::Entry::Entry(const char *field, unsigned field_length)
+		{
+			zero();
+			construct(field, field_length);
+		}
+
+		VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
+		{
+			zero();
+			construct(field_name, field_value, field_value_length);
+		}
+
+		VorbisComment::Entry::Entry(const Entry &entry)
+		{
+			FLAC__ASSERT(entry.is_valid());
+			zero();
+			construct((const char *)entry.entry_.entry, entry.entry_.length);
+		}
+
+		void VorbisComment::Entry::operator=(const Entry &entry)
+		{
+			FLAC__ASSERT(entry.is_valid());
+			clear();
+			construct((const char *)entry.entry_.entry, entry.entry_.length);
+		}
+
+		VorbisComment::Entry::~Entry()
+		{
+			clear();
+		}
+
+		bool VorbisComment::Entry::is_valid() const
+		{
+			return is_valid_;
+		}
+
+		unsigned VorbisComment::Entry::get_field_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return entry_.length;
+		}
+
+		unsigned VorbisComment::Entry::get_field_name_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return field_name_length_;
+		}
+
+		unsigned VorbisComment::Entry::get_field_value_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return field_value_length_;
+		}
+
+		::FLAC__StreamMetadata_VorbisComment_Entry VorbisComment::Entry::get_entry() const
+		{
+			FLAC__ASSERT(is_valid());
+			return entry_;
+		}
+
+		const char *VorbisComment::Entry::get_field() const
+		{
+			FLAC__ASSERT(is_valid());
+			return (const char *)entry_.entry;
+		}
+
+		const char *VorbisComment::Entry::get_field_name() const
+		{
+			FLAC__ASSERT(is_valid());
+			return field_name_;
+		}
+
+		const char *VorbisComment::Entry::get_field_value() const
+		{
+			FLAC__ASSERT(is_valid());
+			return field_value_;
+		}
+
+		bool VorbisComment::Entry::set_field(const char *field, unsigned field_length)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != field);
+
+			clear_entry();
+
+			if(0 == (entry_.entry = (FLAC__byte*)malloc(field_length))) {
+				is_valid_ = false;
+			}
+			else {
+				entry_.length = field_length;
+				memcpy(entry_.entry, field, field_length);
+				(void) parse_field();
+			}
+
+			return is_valid_;
+		}
+
+		bool VorbisComment::Entry::set_field_name(const char *field_name)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != field_name);
+
+			clear_field_name();
+
+			if(0 == (field_name_ = strdup(field_name))) {
+				is_valid_ = false;
+			}
+			else {
+				field_name_length_ = strlen(field_name_);
+				compose_field();
+			}
+
+			return is_valid_;
+		}
+
+		bool VorbisComment::Entry::set_field_value(const char *field_value, unsigned field_value_length)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(0 != field_value);
+
+			clear_field_value();
+
+			if(0 == (field_value_ = (char *)malloc(field_value_length))) {
+				is_valid_ = false;
+			}
+			else {
+				field_value_length_ = field_value_length;
+				memcpy(field_value_, field_value, field_value_length);
+				compose_field();
+			}
+
+			return is_valid_;
+		}
+
+		void VorbisComment::Entry::zero()
+		{
+			is_valid_ = true;
+			entry_.length = 0;
+			entry_.entry = 0;
+			field_name_ = 0;
+			field_name_length_ = 0;
+			field_value_ = 0;
+			field_value_length_ = 0;
+		}
+
+		void VorbisComment::Entry::clear()
+		{
+			clear_entry();
+			clear_field_name();
+			clear_field_value();
+			is_valid_ = true;
+		}
+
+		void VorbisComment::Entry::clear_entry()
+		{
+			if(0 != entry_.entry) {
+				free(entry_.entry);
+				entry_.entry = 0;
+				entry_.length = 0;
+			}
+		}
+
+		void VorbisComment::Entry::clear_field_name()
+		{
+			if(0 != field_name_) {
+				free(field_name_);
+				field_name_ = 0;
+				field_name_length_ = 0;
+			}
+		}
+
+		void VorbisComment::Entry::clear_field_value()
+		{
+			if(0 != field_value_) {
+				free(field_value_);
+				field_value_ = 0;
+				field_value_length_ = 0;
+			}
+		}
+
+		void VorbisComment::Entry::construct(const char *field, unsigned field_length)
+		{
+			if(set_field(field, field_length))
+				parse_field();
+		}
+
+		void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
+		{
+			if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
+				compose_field();
+		}
+
+		void VorbisComment::Entry::compose_field()
+		{
+			clear_entry();
+
+			if(0 == (entry_.entry = (FLAC__byte*)malloc(field_name_length_ + 1 + field_value_length_))) {
+				is_valid_ = false;
+			}
+			else {
+				memcpy(entry_.entry, field_name_, field_name_length_);
+				entry_.length += field_name_length_;
+				memcpy(entry_.entry + entry_.length, "=", 1);
+				entry_.length += 1;
+				memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
+				entry_.length += field_value_length_;
+				is_valid_ = true;
+			}
+		}
+
+		void VorbisComment::Entry::parse_field()
+		{
+			clear_field_name();
+			clear_field_value();
+
+			const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
+
+			if(0 == p)
+				p = (const char *)entry_.entry + entry_.length;
+
+			field_name_length_ = p - (const char *)entry_.entry;
+			if(0 == (field_name_ = (char *)malloc(field_name_length_ + 1))) { // +1 for the trailing \0
+				is_valid_ = false;
+				return;
+			}
+			memcpy(field_name_, entry_.entry, field_name_length_);
+			field_name_[field_name_length_] = '\0';
+
+			if(entry_.length - field_name_length_ == 0) {
+				field_value_length_ = 0;
+				if(0 == (field_value_ = (char *)malloc(0))) {
+					is_valid_ = false;
+					return;
+				}
+			}
+			else {
+				field_value_length_ = entry_.length - field_name_length_ - 1;
+				if(0 == (field_value_ = (char *)malloc(field_value_length_))) {
+					is_valid_ = false;
+					return;
+				}
+				memcpy(field_value_, ++p, field_value_length_);
+			}
+
+			is_valid_ = true;
+		}
+
+
+		//
+		// VorbisComment
+		//
+
+		VorbisComment::VorbisComment():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false)
+		{ }
+
+		VorbisComment::~VorbisComment()
+		{ }
+
+		unsigned VorbisComment::get_num_comments() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.vorbis_comment.num_comments;
+		}
+
+		VorbisComment::Entry VorbisComment::get_vendor_string() const
+		{
+			FLAC__ASSERT(is_valid());
+			return Entry((const char *)object_->data.vorbis_comment.vendor_string.entry, object_->data.vorbis_comment.vendor_string.length);
+		}
+
+		VorbisComment::Entry VorbisComment::get_comment(unsigned index) const
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
+			return Entry((const char *)object_->data.vorbis_comment.comments[index].entry, object_->data.vorbis_comment.comments[index].length);
+		}
+
+		bool VorbisComment::set_vendor_string(const VorbisComment::Entry &entry)
+		{
+			FLAC__ASSERT(is_valid());
+			// vendor_string is a special kind of entry
+			::FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
+			vendor_string.length = entry.get_field_name_length();
+			vendor_string.entry = (FLAC__byte*)entry.get_field_name(); // we can cheat on const-ness because we make a copy below:
+			return (bool)::FLAC__metadata_object_vorbiscomment_set_vendor_string(object_, vendor_string, /*copy=*/true);
+		}
+
+		bool VorbisComment::set_comment(unsigned index, const VorbisComment::Entry &entry)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
+			return (bool)::FLAC__metadata_object_vorbiscomment_set_comment(object_, index, entry.get_entry(), /*copy=*/true);
+		}
+
+		bool VorbisComment::insert_comment(unsigned index, const VorbisComment::Entry &entry)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(index <= object_->data.vorbis_comment.num_comments);
+			return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
+		}
+
+		bool VorbisComment::delete_comment(unsigned index)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(index < object_->data.vorbis_comment.num_comments);
+			return (bool)::FLAC__metadata_object_vorbiscomment_delete_comment(object_, index);
+		}
+
+
+		// ============================================================
+		//
+		//  Level 0
+		//
+		// ============================================================
+
+		bool get_streaminfo(const char *filename, StreamInfo &streaminfo)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata s;
+
+			if(::FLAC__metadata_get_streaminfo(filename, &s)) {
+				streaminfo = s;
+				return true;
+			}
+			else
+				return false;
+		}
+
+
+		// ============================================================
+		//
+		//  Level 1
+		//
+		// ============================================================
+
+		SimpleIterator::SimpleIterator():
+		iterator_(::FLAC__metadata_simple_iterator_new())
+		{ }
+
+		SimpleIterator::~SimpleIterator()
+		{
+			clear();
+		}
+
+		void SimpleIterator::clear()
+		{
+			if(0 != iterator_)
+				FLAC__metadata_simple_iterator_delete(iterator_);
+			iterator_ = 0;
+		}
+
+		bool SimpleIterator::init(const char *filename, bool preserve_file_stats)
+		{
+			FLAC__ASSERT(0 != filename);
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_simple_iterator_init(iterator_, filename, preserve_file_stats);
+		}
+
+		bool SimpleIterator::is_valid() const
+		{
+			return 0 != iterator_;
+		}
+
+		SimpleIterator::Status SimpleIterator::status()
+		{
+			FLAC__ASSERT(is_valid());
+			return Status(::FLAC__metadata_simple_iterator_status(iterator_));
+		}
+
+		bool SimpleIterator::is_writable() const
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_simple_iterator_is_writable(iterator_);
+		}
+
+		bool SimpleIterator::next()
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_simple_iterator_next(iterator_);
+		}
+
+		bool SimpleIterator::prev()
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_simple_iterator_prev(iterator_);
+		}
+
+		::FLAC__MetadataType SimpleIterator::get_block_type() const
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
+		}
+
+		Prototype *SimpleIterator::get_block()
+		{
+			FLAC__ASSERT(is_valid());
+			return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
+		}
+
+		bool SimpleIterator::set_block(Prototype *block, bool use_padding)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_simple_iterator_set_block(iterator_, block->object_, use_padding);
+		}
+
+		bool SimpleIterator::insert_block_after(Prototype *block, bool use_padding)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->object_, use_padding);
+		}
+
+		bool SimpleIterator::delete_block(bool use_padding)
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
+		}
+
+
+		// ============================================================
+		//
+		//  Level 2
+		//
+		// ============================================================
+
+		Chain::Chain():
+		chain_(::FLAC__metadata_chain_new())
+		{ }
+
+		Chain::~Chain()
+		{
+			clear();
+		}
+
+		void Chain::clear()
+		{
+			if(0 != chain_)
+				FLAC__metadata_chain_delete(chain_);
+			chain_ = 0;
+		}
+
+		bool Chain::is_valid() const
+		{
+			return 0 != chain_;
+		}
+
+		Chain::Status Chain::status()
+		{
+			FLAC__ASSERT(is_valid());
+			return Status(::FLAC__metadata_chain_status(chain_));
+		}
+
+		bool Chain::read(const char *filename)
+		{
+			FLAC__ASSERT(0 != filename);
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_chain_read(chain_, filename);
+		}
+
+		bool Chain::write(bool use_padding, bool preserve_file_stats)
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
+		}
+
+		void Chain::merge_padding()
+		{
+			FLAC__ASSERT(is_valid());
+			::FLAC__metadata_chain_merge_padding(chain_);
+		}
+
+		void Chain::sort_padding()
+		{
+			FLAC__ASSERT(is_valid());
+			::FLAC__metadata_chain_sort_padding(chain_);
+		}
+
+
+		Iterator::Iterator():
+		iterator_(::FLAC__metadata_iterator_new())
+		{ }
+
+		Iterator::~Iterator()
+		{
+			clear();
+		}
+
+		void Iterator::clear()
+		{
+			if(0 != iterator_)
+				FLAC__metadata_iterator_delete(iterator_);
+			iterator_ = 0;
+		}
+
+		bool Iterator::is_valid() const
+		{
+			return 0 != iterator_;
+		}
+
+		void Iterator::init(Chain &chain)
+		{
+			FLAC__ASSERT(is_valid());
+			FLAC__ASSERT(chain.is_valid());
+			::FLAC__metadata_iterator_init(iterator_, chain.chain_);
+		}
+
+		bool Iterator::next()
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_iterator_next(iterator_);
+		}
+
+		bool Iterator::prev()
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_iterator_prev(iterator_);
+		}
+
+		::FLAC__MetadataType Iterator::get_block_type() const 
+		{
+			FLAC__ASSERT(is_valid());
+			return ::FLAC__metadata_iterator_get_block_type(iterator_);
+		}
+
+		Prototype *Iterator::get_block()
+		{
+			FLAC__ASSERT(is_valid());
+			Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
+			if(0 != block)
+				block->set_reference(true);
+			return block;
+		}
+
+		bool Iterator::set_block(Prototype *block)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			bool ret = (bool)::FLAC__metadata_iterator_set_block(iterator_, block->object_);
+			if(ret) {
+				block->set_reference(true);
+				delete block;
+			}
+			return ret;
+		}
+
+		bool Iterator::delete_block(bool replace_with_padding)
+		{
+			FLAC__ASSERT(is_valid());
+			return (bool)::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
+		}
+
+		bool Iterator::insert_block_before(Prototype *block)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->object_);
+			if(ret) {
+				block->set_reference(true);
+				delete block;
+			}
+			return ret;
+		}
+
+		bool Iterator::insert_block_after(Prototype *block)
+		{
+			FLAC__ASSERT(0 != block);
+			FLAC__ASSERT(is_valid());
+			bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->object_);
+			if(ret) {
+				block->set_reference(true);
+				delete block;
+			}
+			return ret;
+		}
+
+	};
+};
+#endif
diff --git a/include/FLAC/file_decoder.h b/include/FLAC/file_decoder.h
index c9d415d..af7fa94 100644
--- a/include/FLAC/file_decoder.h
+++ b/include/FLAC/file_decoder.h
@@ -188,7 +188,7 @@
  * \assert
  *    \code decoder != NULL \endcode
  */
-void FLAC__file_decoder_delete(FLAC__FileDecoder *);
+void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder);
 
 
 /***********************************************************************
diff --git a/include/FLAC/format.h b/include/FLAC/format.h
index fae3019..e30a47a 100644
--- a/include/FLAC/format.h
+++ b/include/FLAC/format.h
@@ -426,11 +426,22 @@
 
 /** An enumeration of the available metadata block types. */
 typedef enum {
+
 	FLAC__METADATA_TYPE_STREAMINFO = 0,
+	/**< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block */
+
 	FLAC__METADATA_TYPE_PADDING = 1,
+	/**< <A HREF="../format.html#metadata_block_padding"PADDING</A> block */
+
 	FLAC__METADATA_TYPE_APPLICATION = 2,
+	/**< <A HREF="../format.html#metadata_block_application"APPLICATION</A> block */
+
 	FLAC__METADATA_TYPE_SEEKTABLE = 3,
-	FLAC__METADATA_TYPE_VORBIS_COMMENT = 4
+	/**< <A HREF="../format.html#metadata_block_seektable"SEEKTABLE</A> block */
+
+	FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
+	/**< <A HREF="../format.html#metadata_block_vorbis_comment"VORBISCOMMENT</A> block */
+
 } FLAC__MetadataType;
 
 /** Maps a FLAC__MetadataType to a C string.
@@ -440,6 +451,7 @@
  */
 extern const char * const FLAC__MetadataTypeString[];
 
+
 /** FLAC STREAMINFO structure.  (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
  */
 typedef struct {
diff --git a/include/FLAC/stream_decoder.h b/include/FLAC/stream_decoder.h
index f43edfe..843ff71 100644
--- a/include/FLAC/stream_decoder.h
+++ b/include/FLAC/stream_decoder.h
@@ -37,7 +37,7 @@
  *  \link flac_stream_decoder stream decoder \endlink module.
  */
 
-/** \defgroup flac_decoder FLAC/*_decoder.h: decoder interfaces
+/** \defgroup flac_decoder FLAC/ *_decoder.h: decoder interfaces
  *  \ingroup flac
  *
  *  \brief
diff --git a/include/FLAC/stream_encoder.h b/include/FLAC/stream_encoder.h
index 6380e9a..8c2fa7a 100644
--- a/include/FLAC/stream_encoder.h
+++ b/include/FLAC/stream_encoder.h
@@ -37,7 +37,7 @@
  *  \link flac_stream_encoder stream encoder \endlink module.
  */
 
-/** \defgroup flac_encoder FLAC/*_encoder.h: encoder interfaces
+/** \defgroup flac_encoder FLAC/ *_encoder.h: encoder interfaces
  *  \ingroup flac
  *
  *  \brief
@@ -48,11 +48,6 @@
  * within a file while encoding seemed like too obscure a feature.
  */
 
-/** \defgroup flac_encoder FLAC/*_encoder.h: encoder interfaces
- *  \ingroup flac
- *
- */
-
 /** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface
  *  \ingroup flac_encoder
  *