implement new CUESHEET metadata block
diff --git a/include/FLAC/format.h b/include/FLAC/format.h
index 15d2d17..b4eb887 100644
--- a/include/FLAC/format.h
+++ b/include/FLAC/format.h
@@ -449,16 +449,19 @@
 	/**< <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 */
+	/**< <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 */
+	/**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
 
 	FLAC__METADATA_TYPE_SEEKTABLE = 3,
-	/**< <A HREF="../format.html#metadata_block_seektable"SEEKTABLE</A> block */
+	/**< <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 */
+	/**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block */
+
+	FLAC__METADATA_TYPE_CUESHEET = 5
+	/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
 
 } FLAC__MetadataType;
 
@@ -582,6 +585,82 @@
 extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
 
 
+/** XXX.  (c.f. <A HREF="../format.html#XXX">format specification</A>)
+ */
+typedef struct {
+	FLAC__uint64 offset;
+	/**< The index offset from the beginning of the track, in samples.
+	 * For CD-DA, the offset must be evenly divisible by 588 samples (588
+	 * samples = 44100 samples/sec * 1/75th of a sec)
+	 */
+
+	FLAC__byte number;
+	/**< The index number.  For CD-DA, an index number of 0 corresponds
+	 * to the track pregap.  There must be at least one index in a track.
+	 * The first index in a track must be 0 or 1 and subsequently index
+	 * numbers must increase by 1.
+	 */
+} FLAC__StreamMetadata_CueSheet_Index;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == @@@@3*8 (bits) */
+
+
+/** XXX.  (c.f. <A HREF="../format.html#XXX">format specification</A>)
+ */
+typedef struct {
+	FLAC__uint64 offset;
+	/**< The track offset from the beginning of the audio data, in samples.
+	 * This track offset is the offset to the first index point of the
+	 * track.  Note that for CD-DA, the track's offset in the TOC is that
+	 * of the track's INDEX 01 even if there is an INDEX 00.
+	 *
+	 * For CD-DA, the offset must be evenly divisible by 588 samples (588
+	 * samples = 44100 samples/sec * 1/75th of a sec)
+	 */
+
+	FLAC__byte number;
+	/**< The track number.  A track number of 0 is not allowed to avoid
+	 * conflicting with the CD-DA spec, which reserves this for the
+	 * lead-in. For CD-DA the number must be 1-99, or 170 for the lead-out.
+	 * It is not required but encouraged to start with track 1 and increase
+	 * sequentially.  A CUESHEET block is required to have a lead-out
+	 * track; it is always the last track in the cuesheet and the number
+	 * must be 170 for CD-DA.
+	 */
+
+	char isrc[13]; /*@@@@ 12 ascii characters plus trailing '\0' */
+	unsigned type:1;			/*@@@@q-channel control bit 3: 0=>audio, 1=>data (undefined for CD-DA, defined for CDROM) */
+	unsigned pre_emphasis:1;	/*@@@@q-channel control bit 5: 0=>no pre-em, 1=>pre-em */
+	unsigned reserved:6;
+	FLAC__byte num_indices;
+	FLAC__StreamMetadata_CueSheet_Index *indices;
+} FLAC__StreamMetadata_CueSheet_Track;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+@@@@12*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
+
+
+/** FLAC CUESHEET structure.  (c.f. <A HREF="../format.html#metadata_block_cuesheet">format specification</A>)
+ */
+typedef struct {
+	char media_catalog_number[129]; /*@@@@ for CD-DA: 13 ascii digits ('0'-'9') plus 116 trailing '\0' characters */
+	FLAC__uint64 lead_in;	/*@@@@ length of lead-in in samples; required to compute some versions of CD TOC hashes; CD-DA says the lead-in must be digital silence and rippers don't save it by convention, so TRACK 00 is disallowed and instead we store only the length.  The lead-in is the number of samples up to the first index point of the first track, \b not INDEX 01 of the first track.  This is so applications can correctly compute a CD-DA TOC equivalent even when there is TRACK 01 INDEX 00 data. */
+	unsigned num_tracks;
+	FLAC__StreamMetadata_CueSheet_Track *tracks;
+} FLAC__StreamMetadata_CueSheet;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
+
+
 /** FLAC metadata block structure.  (c.f. <A HREF="../format.html#metadata_block">format specification</A>)
  */
 typedef struct {
@@ -601,6 +680,7 @@
 		FLAC__StreamMetadata_Application application;
 		FLAC__StreamMetadata_SeekTable seek_table;
 		FLAC__StreamMetadata_VorbisComment vorbis_comment;
+		FLAC__StreamMetadata_CueSheet cue_sheet;
 	} data;
 	/**< Polymorphic block data; use the \a type value to determine which
 	 * to use. */
@@ -658,6 +738,27 @@
  */
 FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
 
+/*@@@@ add to unit tests */
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  cue sheet.
+ *
+ * \param cue_sheet  A pointer to an existing cue sheet to be checked.
+ * \param check_cd_da_subset  If \c true, check CUESHEET against more
+ *                   stringent requirements for a CD-DA (audio) disc.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code cue_sheet != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation);
+
 /* \} */
 
 #ifdef __cplusplus
diff --git a/include/FLAC/metadata.h b/include/FLAC/metadata.h
index f1392d0..3f414c8 100644
--- a/include/FLAC/metadata.h
+++ b/include/FLAC/metadata.h
@@ -1231,7 +1231,7 @@
  */
 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
 
-/*@@@@ needs unit test still */
+/*@@@@ add to unit tests */
 /** Check if the given Vorbis comment entry's field name matches the given
  *  field name.
  *
@@ -1247,7 +1247,7 @@
  */
 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, unsigned field_name_length);
 
-/*@@@@ needs unit test still */
+/*@@@@ add to unit tests */
 /** Find a Vorbis comment with the given field name.
  *
  *  The search begins at entry number \a offset; use and offset of 0 to
@@ -1266,7 +1266,7 @@
  */
 FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
 
-/*@@@@ needs unit test still */
+/*@@@@ add to unit tests */
 /** Remove first Vorbis comment matching the given field name.
  *
  * \param object      A pointer to an existing VORBIS_COMMENT object.
@@ -1280,7 +1280,7 @@
  */
 FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name);
 
-/*@@@@ needs unit test still */
+/*@@@@ add to unit tests */
 /** Remove all Vorbis comments matching the given field name.
  *
  * \param object      A pointer to an existing VORBIS_COMMENT object.
@@ -1294,6 +1294,49 @@
  */
 FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name);
 
+/*@@@@ document, add to unit tests */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices);
+
+/*@@@@ document, add to unit tests */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index);
+
+/*@@@@ document, add to unit tests */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+
+/*@@@@ document */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks);
+
+/*@@@@ document */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track track, FLAC__bool copy);
+
+/*@@@@ document */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track track, FLAC__bool copy);
+
+/*@@@@ document */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
+
+/*@@@@ add to unit tests */
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  cue sheet.
+ *
+ * \param object     A pointer to an existing CUESHEET object.
+ * \param check_cd_da_subset  If \c true, check CUESHEET against more
+ *                   stringent requirements for a CD-DA (audio) disc.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__bool
+ *    \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation);
+
 /* \} */
 
 #ifdef __cplusplus
diff --git a/src/libFLAC/format.c b/src/libFLAC/format.c
index b1da684..c76f799 100644
--- a/src/libFLAC/format.c
+++ b/src/libFLAC/format.c
@@ -67,6 +67,22 @@
 FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
 FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
 
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits @@@@3*/
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+12*8; /* bits @@@@12*/
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
+
 FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
 FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
 FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
@@ -216,6 +232,80 @@
 	return j;
 }
 
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
+{
+	unsigned i, j;
+
+	if(check_cd_da_subset) {
+		if(cue_sheet->lead_in < 2 * 44100) {
+			if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
+			return false;
+		}
+		if(cue_sheet->lead_in % 588 != 0) {
+			if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
+			return false;
+		}
+	}
+
+	if(cue_sheet->num_tracks == 0) {
+		if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
+		return false;
+	}
+
+	if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
+		if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
+		return false;
+	}
+
+	for(i = 0; i < cue_sheet->num_tracks; i++) {
+		if(cue_sheet->tracks[i].number == 0) {
+			if(violation) *violation = "cue sheet may not have a track number 0";
+			return false;
+		}
+
+		if(check_cd_da_subset) {
+			if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
+				if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
+				return false;
+			}
+		}
+
+		if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
+			if(violation) *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
+			return false;
+		}
+
+		if(cue_sheet->tracks[i].num_indices == 0) {
+			if(violation) *violation = "cue sheet track must have at least one index point";
+			return false;
+		}
+
+		if(cue_sheet->tracks[i].indices[0].number > 1) {
+			if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
+			return false;
+		}
+
+		for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
+			if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
+				if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
+				return false;
+			}
+
+			if(j > 0) {
+				if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
+					if(violation) *violation = "cue sheet track index numbers must increase by 1";
+					return false;
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+/*
+ * These routines are private to libFLAC
+ */
 unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
 {
 	return
diff --git a/src/libFLAC/metadata_object.c b/src/libFLAC/metadata_object.c
index 099113c..9adb6f5 100644
--- a/src/libFLAC/metadata_object.c
+++ b/src/libFLAC/metadata_object.c
@@ -66,6 +66,23 @@
 	return true;
 }
 
+static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
+{
+	memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+	if(0 == from->indices) {
+		FLAC__ASSERT(from->num_indices == 0);
+	}
+	else {
+		FLAC__StreamMetadata_CueSheet_Index *x;
+		FLAC__ASSERT(from->num_indices > 0);
+		if(0 == (x = (FLAC__StreamMetadata_CueSheet_Index*)malloc(from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+			return false;
+		memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+		to->indices = x;
+	}
+	return true;
+}
+
 static void seektable_calculate_length_(FLAC__StreamMetadata *object)
 {
 	FLAC__ASSERT(0 != object);
@@ -142,13 +159,6 @@
 	if(0 != return_array) {
 		unsigned i;
 
-		/* Need to do this to set the pointers inside the comments to 0.
-		 * In case of an error in the following loop, the object will be
-		 * deleted and we don't want the destructor freeing uninitialized
-		 * pointers.
-		 */
-		memset(return_array, 0, num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
-
 		for(i = 0; i < num_comments; i++) {
 			if(!copy_vcentry_(return_array+i, object_array+i)) {
 				vorbiscomment_entry_array_delete_(return_array, num_comments);
@@ -188,6 +198,120 @@
 	return true;
 }
 
+static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
+{
+	unsigned i;
+
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	object->length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+
+	object->length += object->data.cue_sheet.num_tracks * (
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+	) / 8;
+
+	for(i = 0; i < object->data.cue_sheet.num_tracks; i++) {
+		object->length += object->data.cue_sheet.tracks[i].num_indices * (
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+		) / 8;
+	}
+}
+
+static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsigned num_indices)
+{
+	FLAC__ASSERT(num_indices > 0);
+
+	return (FLAC__StreamMetadata_CueSheet_Index*)calloc(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
+{
+	FLAC__ASSERT(num_tracks > 0);
+
+	return (FLAC__StreamMetadata_CueSheet_Track*)calloc(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
+{
+	unsigned i;
+
+	FLAC__ASSERT(0 != object_array && num_tracks > 0);
+
+	for(i = 0; i < num_tracks; i++) {
+		if(0 != object_array[i].indices) {
+			FLAC__ASSERT(object_array[i].num_indices > 0);
+			free(object_array[i].indices);
+		}
+	}
+
+	if(0 != object_array)
+		free(object_array);
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
+{
+	FLAC__StreamMetadata_CueSheet_Track *return_array;
+
+	FLAC__ASSERT(0 != object_array);
+	FLAC__ASSERT(num_tracks > 0);
+
+	return_array = cuesheet_track_array_new_(num_tracks);
+
+	if(0 != return_array) {
+		unsigned i;
+
+		for(i = 0; i < num_tracks; i++) {
+			if(!copy_track_(return_array+i, object_array+i)) {
+				cuesheet_track_array_delete_(return_array, num_tracks);
+				return 0;
+			}
+		}
+	}
+
+	return return_array;
+}
+
+static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_CueSheet_Index *save;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(0 != dest);
+	FLAC__ASSERT(0 != src);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT((0 != src->indices && src->num_indices > 0) || (0 == src->indices && src->num_indices == 0));
+	/*@@@@ for docs, note that there is no "&& copy == false" at the end here ^^^ which will filter up */
+
+	save = dest->indices;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(!copy_track_(dest, src))
+			return false;
+	}
+	else {
+		*dest = *src;
+	}
+
+	if(0 != save)
+		free(save);
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
 
 /****************************************************************************
  *
@@ -219,13 +343,12 @@
 						free(object);
 						return 0;
 					}
-					object->length =
-						(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8) +
-						object->data.vorbis_comment.vendor_string.length +
-						(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8)
-					;
+					vorbiscomment_calculate_length_(object);
 				}
 				break;
+			case FLAC__METADATA_TYPE_CUESHEET:
+				cuesheet_calculate_length_(object);
+				break;
 			default:
 				/* double protection: */
 				FLAC__ASSERT(0);
@@ -288,6 +411,20 @@
 				}
 				to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
 				break;
+			case FLAC__METADATA_TYPE_CUESHEET:
+				memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
+				if(object->data.cue_sheet.num_tracks == 0) {
+					FLAC__ASSERT(0 == object->data.cue_sheet.tracks);
+				}
+				else {
+					FLAC__ASSERT(0 != object->data.cue_sheet.tracks);
+					to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+					if(0 == to->data.cue_sheet.tracks) {
+						FLAC__metadata_object_delete(to);
+						return 0;
+					}
+				}
+				break;
 			default:
 				/* double protection: */
 				FLAC__ASSERT(0);
@@ -323,6 +460,12 @@
 				vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
 			}
 			break;
+		case FLAC__METADATA_TYPE_CUESHEET:
+			if(0 != object->data.cue_sheet.tracks) {
+				FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+				cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+			}
+			break;
 		default:
 			FLAC__ASSERT(0);
 	}
@@ -424,6 +567,52 @@
 	return true;
 }
 
+static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
+{
+	unsigned i, j;
+
+	if(0 != strcmp(block1->media_catalog_number, block2->media_catalog_number))
+		return false;
+
+	if(block1->lead_in != block2->lead_in)
+		return false;
+
+	if(block1->num_tracks != block2->num_tracks)
+		return false;
+
+	if(0 != block1->tracks && 0 != block2->tracks) {
+		FLAC__ASSERT(block1->num_tracks > 0);
+		for(i = 0; i < block1->num_tracks; i++) {
+			if(block1->tracks[i].offset != block2->tracks[i].offset)
+				return false;
+			if(block1->tracks[i].number != block2->tracks[i].number)
+				return false;
+			if(0 != memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)))
+				return false;
+			if(block1->tracks[i].type != block2->tracks[i].type)
+				return false;
+			if(block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
+				return false;
+			if(block1->tracks[i].num_indices != block2->tracks[i].num_indices)
+				return false;
+			if(0 != block1->tracks[i].indices && 0 != block2->tracks[i].indices) {
+				FLAC__ASSERT(block1->tracks[i].num_indices > 0);
+				for(j = 0; j < block1->tracks[i].num_indices; j++) {
+					if(block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
+						return false;
+					if(block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
+						return false;
+				}
+			}
+			else if(block1->tracks[i].indices != block2->tracks[i].indices)
+				return false;
+		}
+	}
+	else if(block1->tracks != block2->tracks)
+		return false;
+	return true;
+}
+
 FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
 {
 	FLAC__ASSERT(0 != block1);
@@ -449,6 +638,8 @@
 			return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
 		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
 			return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
 		default:
 			FLAC__ASSERT(0);
 			return false;
@@ -527,7 +718,7 @@
 {
 	FLAC__ASSERT(0 != object);
 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-	FLAC__ASSERT(object->data.seek_table.num_points > point_num);
+	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
 
 	object->data.seek_table.points[point_num] = point;
 }
@@ -538,7 +729,7 @@
 
 	FLAC__ASSERT(0 != object);
 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-	FLAC__ASSERT(object->data.seek_table.num_points >= point_num);
+	FLAC__ASSERT(point_num <= object->data.seek_table.num_points);
 
 	if(!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
 		return false;
@@ -558,7 +749,7 @@
 
 	FLAC__ASSERT(0 != object);
 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
-	FLAC__ASSERT(object->data.seek_table.num_points > point_num);
+	FLAC__ASSERT(point_num < object->data.seek_table.num_points);
 
 	/* move all points > point_num backward one space */
 	for(i = point_num; i < object->data.seek_table.num_points-1; i++)
@@ -728,7 +919,7 @@
 
 	FLAC__ASSERT(0 != object);
 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-	FLAC__ASSERT(object->data.vorbis_comment.num_comments >= comment_num);
+	FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments);
 
 	vc = &object->data.vorbis_comment;
 
@@ -749,7 +940,7 @@
 
 	FLAC__ASSERT(0 != object);
 	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-	FLAC__ASSERT(object->data.vorbis_comment.num_comments > comment_num);
+	FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
 
 	vc = &object->data.vorbis_comment;
 
@@ -833,3 +1024,184 @@
 
 	return ok? (int)matching : -1;
 }
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	if(0 == track->indices) {
+		FLAC__ASSERT(track->num_indices == 0);
+		if(0 == new_num_indices)
+			return true;
+		else if(0 == (track->indices = cuesheet_track_index_array_new_(new_num_indices)))
+			return false;
+	}
+	else {
+		const unsigned old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+		const unsigned new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+
+		FLAC__ASSERT(track->num_indices > 0);
+
+		if(new_size == 0) {
+			free(track->indices);
+			track->indices = 0;
+		}
+		else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(track->indices, new_size)))
+			return false;
+
+		/* if growing, zero all the lengths/pointers of new elements */
+		if(new_size > old_size)
+			memset(track->indices + track->num_indices, 0, new_size - old_size);
+	}
+
+	track->num_indices = new_num_indices;
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+	FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	if(!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
+		return false;
+
+	/* move all indices >= index_num forward one space */
+	memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
+
+	track->indices[index_num] = index;
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+	FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices);
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	/* move all indices > index_num backward one space */
+	memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(track->num_indices-index_num-1));
+
+	FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	if(0 == object->data.cue_sheet.tracks) {
+		FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
+		if(0 == new_num_tracks)
+			return true;
+		else if(0 == (object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)))
+			return false;
+	}
+	else {
+		const unsigned old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+		const unsigned new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+
+		FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+
+		/* if shrinking, free the truncated entries */
+		if(new_num_tracks < object->data.cue_sheet.num_tracks) {
+			unsigned i;
+			for(i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
+				if(0 != object->data.cue_sheet.tracks[i].indices)
+					free(object->data.cue_sheet.tracks[i].indices);
+		}
+
+		if(new_size == 0) {
+			free(object->data.cue_sheet.tracks);
+			object->data.cue_sheet.tracks = 0;
+		}
+		else if(0 == (object->data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)realloc(object->data.cue_sheet.tracks, new_size)))
+			return false;
+
+		/* if growing, zero all the lengths/pointers of new elements */
+		if(new_size > old_size)
+			memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
+	}
+
+	object->data.cue_sheet.num_tracks = new_num_tracks;
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track track, FLAC__bool copy)
+{
+	return cuesheet_set_track_(object, &object->data.cue_sheet.tracks[track_num], &track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track track, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_CueSheet *cs;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks);
+
+	cs = &object->data.cue_sheet;
+
+	if(!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
+		return false;
+
+	/* move all tracks >= track_num forward one space */
+	memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
+	cs->tracks[track_num].num_indices = 0;
+	cs->tracks[track_num].indices = 0;
+
+	return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num)
+{
+	FLAC__StreamMetadata_CueSheet *cs;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+	FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+	cs = &object->data.cue_sheet;
+
+	/* free the track at track_num */
+	if(0 != cs->tracks[track_num].indices)
+		free(cs->tracks[track_num].indices);
+
+	/* move all tracks > track_num backward one space */
+	memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
+	cs->tracks[cs->num_tracks-1].num_indices = 0;
+	cs->tracks[cs->num_tracks-1].indices = 0;
+
+	return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+	return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
+}
diff --git a/src/test_libFLAC/metadata_object.c b/src/test_libFLAC/metadata_object.c
index 215f7b3..258d2bf 100644
--- a/src/test_libFLAC/metadata_object.c
+++ b/src/test_libFLAC/metadata_object.c
@@ -183,11 +183,120 @@
 	vc_calc_len_(block);
 }
 
+static void track_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+	track->offset = offset;
+	track->number = number;
+	memcpy(track->isrc, isrc, sizeof(track->isrc));
+	track->type = data;
+	track->pre_emphasis = pre_em;
+	track->num_indices = 0;
+	track->indices = 0;
+}
+
+static void track_clone_(FLAC__StreamMetadata_CueSheet_Track *track)
+{
+	if(track->num_indices > 0) {
+		size_t bytes = sizeof(FLAC__StreamMetadata_CueSheet_Index) * track->num_indices;
+		FLAC__StreamMetadata_CueSheet_Index *x = (FLAC__StreamMetadata_CueSheet_Index*)malloc(bytes);
+		FLAC__ASSERT(0 != x);
+		memcpy(x, track->indices, bytes);
+		track->indices = x;
+	}
+}
+
+static void cs_calc_len_(FLAC__StreamMetadata *block)
+{
+	const FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+	unsigned i;
+
+	block->length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+	block->length += cs->num_tracks * (
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+	) / 8;
+	for(i = 0; i < cs->num_tracks; i++) {
+		block->length += cs->tracks[i].num_indices * (
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+		) / 8;
+	}
+}
+
+static void cs_resize_(FLAC__StreamMetadata *block, unsigned num)
+{
+	FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+
+	if(cs->num_tracks != 0) {
+		FLAC__ASSERT(0 != cs->tracks);
+		if(num < cs->num_tracks) {
+			unsigned i;
+			for(i = num; i < cs->num_tracks; i++) {
+				if(0 != cs->tracks[i].indices)
+					free(cs->tracks[i].indices);
+			}
+		}
+	}
+	if(num == 0) {
+		if(0 != cs->tracks) {
+			free(cs->tracks);
+			cs->tracks = 0;
+		}
+	}
+	else {
+		cs->tracks = (FLAC__StreamMetadata_CueSheet_Track*)realloc(cs->tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)*num);
+		FLAC__ASSERT(0 != cs->tracks);
+		if(num > cs->num_tracks)
+			memset(cs->tracks+cs->num_tracks, 0, sizeof(FLAC__StreamMetadata_CueSheet_Track)*(num-cs->num_tracks));
+	}
+
+	cs->num_tracks = num;
+	cs_calc_len_(block);
+}
+
+static void cs_set_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, unsigned pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+	track_new_(track, offset, number, isrc, data, pre_em);
+	block->data.cue_sheet.tracks[pos] = *track;
+	cs_calc_len_(block);
+}
+
+static void cs_insert_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, unsigned pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+	cs_resize_(block, block->data.cue_sheet.num_tracks+1);
+	memmove(&block->data.cue_sheet.tracks[pos+1], &block->data.cue_sheet.tracks[pos], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-1-pos));
+	cs_set_new_(track, block, pos, offset, number, isrc, data, pre_em);
+	cs_calc_len_(block);
+}
+
+static void cs_delete_(FLAC__StreamMetadata *block, unsigned pos)
+{
+	if(0 != block->data.cue_sheet.tracks[pos].indices)
+		free(block->data.cue_sheet.tracks[pos].indices);
+	memmove(&block->data.cue_sheet.tracks[pos], &block->data.cue_sheet.tracks[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-pos-1));
+	block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].indices = 0;
+	block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].num_indices = 0;
+	cs_resize_(block, block->data.cue_sheet.num_tracks-1);
+	cs_calc_len_(block);
+}
+
+
 FLAC__bool test_metadata_object()
 {
-	FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment;
+	FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet;
 	FLAC__StreamMetadata_SeekPoint seekpoint_array[8];
 	FLAC__StreamMetadata_VorbisComment_Entry entry;
+	FLAC__StreamMetadata_CueSheet_Track track;
 	unsigned i, expected_length, seekpoints;
 	static FLAC__byte dummydata[4] = { 'a', 'b', 'c', 'd' };
 
@@ -873,5 +982,269 @@
 	printf("OK\n");
 
 
+	printf("testing CUESHEET\n");
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	expected_length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	cuesheet = FLAC__metadata_object_clone(block);
+	if(0 == cuesheet) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	cs_resize_(cuesheet, 2);
+	printf("testing FLAC__metadata_object_cuesheet_resize_tracks(grow to %u)...", cuesheet->data.cue_sheet.num_tracks);
+	if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	cs_resize_(cuesheet, 1);
+	printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks);
+	if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	cs_resize_(cuesheet, 0);
+	printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks);
+	if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on empty array...");
+	cs_insert_new_(&track, cuesheet, 0, 0, 1, "ABCDE1234567", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, track, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on beginning of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 0, 10, 2, "BBCDE1234567", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, track, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on middle of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 1, 20, 3, "CBCDE1234567", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, track, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on end of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 3, 30, 4, "DBCDE1234567", false, false);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, track, /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!compare_block_(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array...");
+	cs_delete_(cuesheet, 2);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+	cs_delete_(cuesheet, 2);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array...");
+	cs_delete_(cuesheet, 0);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_set_track(copy)...");
+	cs_set_new_(&track, cuesheet, 0, 40, 5, "EBCDE1234567", false, false);
+	FLAC__metadata_object_cuesheet_set_track(block, 0, track, /*copy=*/true);
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	/*@@@@ track index function tests here*/
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(cuesheet);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	cuesheet = FLAC__metadata_object_clone(block);
+	if(0 == cuesheet) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on empty array...");
+	cs_insert_new_(&track, cuesheet, 0, 60, 7, "GBCDE1234567", false, false);
+	track_clone_(&track);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, track, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on beginning of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 0, 70, 8, "HBCDE1234567", false, false);
+	track_clone_(&track);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, track, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on middle of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 1, 80, 9, "IBCDE1234567", false, false);
+	track_clone_(&track);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, track, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on end of non-empty array...");
+	cs_insert_new_(&track, cuesheet, 3, 90, 10, "JBCDE1234567", false, false);
+	track_clone_(&track);
+	if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, track, /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array...");
+	cs_delete_(cuesheet, 2);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+	cs_delete_(cuesheet, 2);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array...");
+	cs_delete_(cuesheet, 0);
+	if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_cuesheet_set_track(own)...");
+	cs_set_new_(&track, cuesheet, 0, 100, 11, "KBCDE1234567", false, false);
+	track_clone_(&track);
+	FLAC__metadata_object_cuesheet_set_track(block, 0, track, /*copy=*/false);
+	if(!compare_block_(cuesheet, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(cuesheet);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
 	return true;
 }
diff --git a/src/test_libFLAC/metadata_utils.c b/src/test_libFLAC/metadata_utils.c
index eadd581..ab77755 100644
--- a/src/test_libFLAC/metadata_utils.c
+++ b/src/test_libFLAC/metadata_utils.c
@@ -215,6 +215,69 @@
 	return true;
 }
 
+FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy)
+{
+	unsigned i, j;
+
+	if(0 != strcmp(blockcopy->media_catalog_number, block->media_catalog_number)) {
+		printf("FAILED, media_catalog_number mismatch, expected %s, got %s\n", block->media_catalog_number, blockcopy->media_catalog_number);
+		return false;
+	}
+	if(blockcopy->lead_in != block->lead_in) {
+		printf("FAILED, lead_in mismatch, expected %llu, got %llu\n", block->lead_in, blockcopy->lead_in);
+		return false;
+	}
+	if(blockcopy->num_tracks != block->num_tracks) {
+		printf("FAILED, num_tracks mismatch, expected %u, got %u\n", block->num_tracks, blockcopy->num_tracks);
+		return false;
+	}
+	for(i = 0; i < block->num_tracks; i++) {
+		if(blockcopy->tracks[i].offset != block->tracks[i].offset) {
+			printf("FAILED, tracks[%u].offset mismatch, expected %llu, got %llu\n", i, block->tracks[i].offset, blockcopy->tracks[i].offset);
+			return false;
+		}
+		if(blockcopy->tracks[i].number != block->tracks[i].number) {
+			printf("FAILED, tracks[%u].number mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].number, (unsigned)blockcopy->tracks[i].number);
+			return false;
+		}
+		if(0 != strcmp(blockcopy->tracks[i].isrc, block->tracks[i].isrc)) {
+			printf("FAILED, tracks[%u].number mismatch, expected %s, got %s\n", i, block->tracks[i].isrc, blockcopy->tracks[i].isrc);
+			return false;
+		}
+		if(blockcopy->tracks[i].type != block->tracks[i].type) {
+			printf("FAILED, tracks[%u].type mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].type, (unsigned)blockcopy->tracks[i].type);
+			return false;
+		}
+		if(blockcopy->tracks[i].pre_emphasis != block->tracks[i].pre_emphasis) {
+			printf("FAILED, tracks[%u].pre_emphasis mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].pre_emphasis, (unsigned)blockcopy->tracks[i].pre_emphasis);
+			return false;
+		}
+		if(blockcopy->tracks[i].num_indices != block->tracks[i].num_indices) {
+			printf("FAILED, tracks[%u].num_indices mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].num_indices, (unsigned)blockcopy->tracks[i].num_indices);
+			return false;
+		}
+		if(0 == block->tracks[i].indices || 0 == blockcopy->tracks[i].indices) {
+			if(block->tracks[i].indices != blockcopy->tracks[i].indices) {
+				printf("FAILED, tracks[%u].indices mismatch\n", i);
+				return false;
+			}
+		}
+		else {
+			for(j = 0; j < block->tracks[i].num_indices; j++) {
+				if(blockcopy->tracks[i].indices[j].offset != block->tracks[i].indices[j].offset) {
+					printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %llu, got %llu\n", i, j, block->tracks[i].indices[j].offset, blockcopy->tracks[i].indices[j].offset);
+					return false;
+				}
+				if(blockcopy->tracks[i].indices[j].number != block->tracks[i].indices[j].number) {
+					printf("FAILED, tracks[%u].indices[%u].number mismatch, expected %u, got %u\n", i, j, (unsigned)block->tracks[i].indices[j].number, (unsigned)blockcopy->tracks[i].indices[j].number);
+					return false;
+				}
+			}
+		}
+	}
+	return true;
+}
+
 FLAC__bool compare_block_(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy)
 {
 	if(blockcopy->type != block->type) {
@@ -240,6 +303,8 @@
 			return compare_block_data_seektable_(&block->data.seek_table, &blockcopy->data.seek_table);
 		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
 			return compare_block_data_vorbiscomment_(&block->data.vorbis_comment, &blockcopy->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return compare_block_data_cuesheet_(&block->data.cue_sheet, &blockcopy->data.cue_sheet);
 		default:
 			printf("FAILED, invalid block type %u\n", (unsigned)block->type);
 			return false;
diff --git a/src/test_libFLAC/metadata_utils.h b/src/test_libFLAC/metadata_utils.h
index 03dca57..3fb8fe6 100644
--- a/src/test_libFLAC/metadata_utils.h
+++ b/src/test_libFLAC/metadata_utils.h
@@ -38,6 +38,8 @@
 
 FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy);
 
+FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy);
+
 FLAC__bool compare_block_(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy);
 
 #endif