add FLAC__metadata_get_cuesheet() and FLAC__metadata_object_cuesheet_calculate_cddb_id()
authorJosh Coalson <jcoalson@users.sourceforce.net>
Mon, 10 Apr 2006 05:37:34 +0000 (05:37 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Mon, 10 Apr 2006 05:37:34 +0000 (05:37 +0000)
doc/html/changelog.html
include/FLAC++/metadata.h
include/FLAC/metadata.h
src/libFLAC++/metadata.cpp
src/libFLAC/metadata_iterators.c
src/libFLAC/metadata_object.c
src/test_libFLAC++/metadata_manip.cpp
src/test_libFLAC/metadata_manip.c

index 5713237..99283d4 100644 (file)
                                        <li>
                                                libFLAC:
                                                <ul>
-                                                       <li>(none)</li>
+                                                       <li><b>Added</b> FLAC__metadata_object_cuesheet_calculate_cddb_id()</li>
+                                                       <li><b>Added</b> FLAC__metadata_get_cuesheet()</li>
                                                </ul>
                                        </li>
                                        <li>
                                                libFLAC++:
                                                <ul>
-                                                       <li>(none)</li>
+                                                       <li><b>Added</b> FLAC::Metadata::CueSheet::calculate_cddb_id()</li>
+                                                       <li><b>Added</b> FLAC::Metadata::get_cuesheet()</li>
                                                </ul>
                                        </li>
                                        <li>
index 0e18e94..2da66ca 100644 (file)
@@ -777,6 +777,9 @@ namespace FLAC {
 
                        //! See FLAC__metadata_object_cuesheet_is_legal()
                        bool is_legal(bool check_cd_da_subset = false, const char **violation = 0) const;
+
+                       //! See FLAC__metadata_object_cuesheet_calculate_cddb_id()
+                       FLAC__uint32 calculate_cddb_id() const;
                };
 
                /** Opaque metadata block for storing unknown types.
@@ -859,6 +862,10 @@ namespace FLAC {
                FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags);
                FLACPP_API bool get_tags(const char *filename, VorbisComment &tags);
 
+               //! See FLAC__metadata_get_cuesheet().
+               FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet);
+               FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet);
+
                /* \} */
 
 
index ff40e6d..bf7fd01 100644 (file)
@@ -124,15 +124,15 @@ extern "C" {
  *
  *  \brief
  *  The level 0 interface consists of individual routines to read the
- *  STREAMINFO and VORBIS_COMMENT blocks, requiring only a filename.
+ *  STREAMINFO, VORBIS_COMMENT, and CUESHEET blocks, requiring only a filename.
  *
- *  It skips any ID3v2 tag at the head of the file.
+ *  They try to skip any ID3v2 tag at the head of the file.
  *
  * \{
  */
 
 /** Read the STREAMINFO metadata block of the given FLAC file.  This function
- *  will skip any ID3v2 tag at the head of the file.
+ *  will try to skip any ID3v2 tag at the head of the file.
  *
  * \param filename    The path to the FLAC file to read.
  * \param streaminfo  A pointer to space for the STREAMINFO block.  Since
@@ -151,7 +151,7 @@ extern "C" {
 FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo);
 
 /** Read the VORBIS_COMMENT metadata block of the given FLAC file.  This
- *  function will skip any ID3v2 tag at the head of the file.
+ *  function will try to skip any ID3v2 tag at the head of the file.
  *
  * \param filename    The path to the FLAC file to read.
  * \param tags        The address where the returned pointer will be
@@ -159,7 +159,7 @@ FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__St
  *                    the caller using FLAC__metadata_object_delete().
  * \assert
  *    \code filename != NULL \endcode
- *    \code streaminfo != NULL \endcode
+ *    \code tags != NULL \endcode
  * \retval FLAC__bool
  *    \c true if a valid VORBIS_COMMENT block was read from \a filename,
  *    and \a *tags will be set to the address of the tag structure.
@@ -169,6 +169,25 @@ FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__St
  */
 FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags);
 
+/** Read the CUESHEET metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param cuesheet    The address where the returned pointer will be
+ *                    stored.  The \a cuesheet object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code cuesheet != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid CUESHEET block was read from \a filename,
+ *    and \a *cuesheet will be set to the address of the tag structure.
+ *    Returns \c false if there was a memory allocation error, a file
+ *    decoder error, or the file contained no CUESHEET block, and
+ *    \a *cuesheet will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet);
+
 /* \} */
 
 
@@ -1849,6 +1868,20 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMeta
  */
 FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation);
 
+/* @@@@ add to unit tests */
+/** Calculate and return the CDDB/freedb ID for a cue sheet.  The function
+ *  assumes the cue sheet corresponds to a CD; the result is undefined
+ *  if the cuesheet's is_cd bit is not set.
+ *
+ * \param object     A pointer to an existing CUESHEET object.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__uint32
+ *    The unsigned integer representation of the CDDB/freedb ID
+ */
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object);
+
 /* \} */
 
 #ifdef __cplusplus
index 22acac1..0a64c11 100644 (file)
@@ -1007,6 +1007,12 @@ namespace FLAC {
                        return (bool)::FLAC__metadata_object_cuesheet_is_legal(object_, check_cd_da_subset, violation);
                }
 
+               FLAC__uint32 CueSheet::calculate_cddb_id() const
+               {
+                       FLAC__ASSERT(is_valid());
+                       return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(object_);
+               }
+
 
                //
                // Unknown
@@ -1088,6 +1094,36 @@ namespace FLAC {
                                return false;
                }
 
+               FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata *object;
+
+                       cuesheet = 0;
+
+                       if(::FLAC__metadata_get_cuesheet(filename, &object)) {
+                               cuesheet = new CueSheet(object, /*copy=*/false);
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
+               FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet)
+               {
+                       FLAC__ASSERT(0 != filename);
+
+                       ::FLAC__StreamMetadata *object;
+
+                       if(::FLAC__metadata_get_cuesheet(filename, &object)) {
+                               cuesheet.assign(object, /*copy=*/false);
+                               return true;
+                       }
+                       else
+                               return false;
+               }
+
 
                // ============================================================
                //
index 0f99b77..8d96d96 100644 (file)
@@ -153,31 +153,28 @@ static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecode
 
 typedef struct {
        FLAC__bool got_error;
-       FLAC__bool got_object;
        FLAC__StreamMetadata *object;
 } level0_client_data;
 
-FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
+static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
 {
        level0_client_data cd;
        FLAC__FileDecoder *decoder;
 
        FLAC__ASSERT(0 != filename);
-       FLAC__ASSERT(0 != streaminfo);
+
+       cd.got_error = false;
+       cd.object = 0;
 
        decoder = FLAC__file_decoder_new();
 
        if(0 == decoder)
-               return false;
-
-       cd.got_error = false;
-       cd.got_object = false;
-       cd.object = 0;
+               return 0;
 
        FLAC__file_decoder_set_md5_checking(decoder, false);
        FLAC__file_decoder_set_filename(decoder, filename);
        FLAC__file_decoder_set_metadata_ignore_all(decoder);
-       FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+       FLAC__file_decoder_set_metadata_respond(decoder, type);
        FLAC__file_decoder_set_write_callback(decoder, write_callback_);
        FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
        FLAC__file_decoder_set_error_callback(decoder, error_callback_);
@@ -186,7 +183,7 @@ FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__St
        if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK || cd.got_error) {
                FLAC__file_decoder_finish(decoder);
                FLAC__file_decoder_delete(decoder);
-               return false;
+               return 0;
        }
 
        if(!FLAC__file_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
@@ -194,72 +191,53 @@ FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__St
                FLAC__file_decoder_delete(decoder);
                if(0 != cd.object)
                        FLAC__metadata_object_delete(cd.object);
-               return false;
+               return 0;
        }
 
        FLAC__file_decoder_finish(decoder);
        FLAC__file_decoder_delete(decoder);
 
-       if(cd.got_object) {
-               /* can just copy the contents since STREAMINFO has no internal structure */
-               *streaminfo = *(cd.object);
-       }
-
-       if(0 != cd.object)
-               FLAC__metadata_object_delete(cd.object);
-
-       return cd.got_object;
+       return cd.object;
 }
 
-FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
 {
-       level0_client_data cd;
-       FLAC__FileDecoder *decoder;
+       FLAC__StreamMetadata *object;
 
        FLAC__ASSERT(0 != filename);
-       FLAC__ASSERT(0 != tags);
+       FLAC__ASSERT(0 != streaminfo);
 
-       decoder = FLAC__file_decoder_new();
+       object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
 
-       if(0 == decoder)
+       if (object) {
+               /* can just copy the contents since STREAMINFO has no internal structure */
+               *streaminfo = *object;
+               FLAC__metadata_object_delete(object);
+               return true;
+       }
+       else {
                return false;
+       }
+}
 
-       *tags = 0;
-
-       cd.got_error = false;
-       cd.got_object = false;
-       cd.object = 0;
-
-       FLAC__file_decoder_set_md5_checking(decoder, false);
-       FLAC__file_decoder_set_filename(decoder, filename);
-       FLAC__file_decoder_set_metadata_ignore_all(decoder);
-       FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
-       FLAC__file_decoder_set_write_callback(decoder, write_callback_);
-       FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
-       FLAC__file_decoder_set_error_callback(decoder, error_callback_);
-       FLAC__file_decoder_set_client_data(decoder, &cd);
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != tags);
 
-       if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK || cd.got_error) {
-               FLAC__file_decoder_finish(decoder);
-               FLAC__file_decoder_delete(decoder);
-               return false;
-       }
+       *tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
 
-       if(!FLAC__file_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
-               FLAC__file_decoder_finish(decoder);
-               FLAC__file_decoder_delete(decoder);
-               if(0 != cd.object)
-                       FLAC__metadata_object_delete(cd.object);
-               return false;
-       }
+       return 0 != *tags;
+}
 
-       FLAC__file_decoder_finish(decoder);
-       FLAC__file_decoder_delete(decoder);
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
+{
+       FLAC__ASSERT(0 != filename);
+       FLAC__ASSERT(0 != cuesheet);
 
-       if(cd.got_object)
-               *tags = cd.object;
+       *cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
 
-       return cd.got_object;
+       return 0 != *cuesheet;
 }
 
 FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
@@ -278,11 +256,9 @@ void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMeta
         * we assume we only get here when the one metadata block we were
         * looking for was passed to us
         */
-       if(!cd->got_object) {
+       if(!cd->got_error && 0 == cd->object) {
                if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
                        cd->got_error = true;
-               else
-                       cd->got_object = true;
        }
 }
 
index 333889a..c758627 100644 (file)
@@ -1470,3 +1470,49 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMe
 
        return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
 }
+
+static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, unsigned track)
+{
+       if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1)
+               return 0;
+       else if (cs->tracks[track].indices[0].number == 1)
+               return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in;
+       else if (cs->tracks[track].num_indices < 2)
+               return 0;
+       else if (cs->tracks[track].indices[1].number == 1)
+               return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in;
+       else
+               return 0;
+}
+
+static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x)
+{
+       FLAC__uint32 n = 0;
+       while (x) {
+               n += (x%10);
+               x /= 10;
+       }
+       return n;
+}
+
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object)
+{
+       const FLAC__StreamMetadata_CueSheet *cs;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+       cs = &object->data.cue_sheet;
+
+       if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */
+               return 0;
+
+       {
+               FLAC__uint32 i, length, sum = 0;
+               for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */
+                       sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100));
+               length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100);
+
+               return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
+       }
+}
index 801a258..0a8dced 100644 (file)
@@ -471,10 +471,11 @@ void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status)
        printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
 }
 
-static bool generate_file_()
+static bool generate_file_(FLAC__bool include_cuesheet)
 {
-       ::FLAC__StreamMetadata streaminfo, vorbiscomment, padding;
-       ::FLAC__StreamMetadata *metadata[1];
+       ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding;
+       ::FLAC__StreamMetadata *metadata[3];
+       unsigned i = 0, n = 0;
 
        printf("generating FLAC file for test\n");
 
@@ -497,7 +498,7 @@ static bool generate_file_()
        {
                const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
                vorbiscomment.is_last = false;
-               vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+               vorbiscomment.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
                vorbiscomment.length = (4 + vendor_string_length) + 4;
                vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
                vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
@@ -506,23 +507,42 @@ static bool generate_file_()
                vorbiscomment.data.vorbis_comment.comments = 0;
        }
 
+       {
+               if (0 == (cuesheet = ::FLAC__metadata_object_new(::FLAC__METADATA_TYPE_CUESHEET)))
+                       return die_("priming our metadata");
+               cuesheet->is_last = false;
+               strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
+               cuesheet->data.cue_sheet.lead_in = 123;
+               cuesheet->data.cue_sheet.is_cd = false;
+               if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
+                       return die_("priming our metadata");
+               cuesheet->data.cue_sheet.tracks[0].number = 1;
+               if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
+                       return die_("priming our metadata");
+       }
+
        padding.is_last = true;
        padding.type = ::FLAC__METADATA_TYPE_PADDING;
        padding.length = 1234;
 
-       metadata[0] = &padding;
+       metadata[n++] = &vorbiscomment;
+       if (include_cuesheet)
+               metadata[n++] = cuesheet;
+       metadata[n++] = &padding;
 
        FLAC::Metadata::StreamInfo s(&streaminfo);
        FLAC::Metadata::VorbisComment v(&vorbiscomment);
+       FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
        FLAC::Metadata::Padding p(&padding);
        if(
-               !insert_to_our_metadata_(&s, 0, /*copy=*/true) ||
-               !insert_to_our_metadata_(&v, 1, /*copy=*/true) ||
-               !insert_to_our_metadata_(&p, 2, /*copy=*/true)
+               !insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
+               !insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
+               (include_cuesheet && !insert_to_our_metadata_(&v, i++, /*copy=*/true)) ||
+               !insert_to_our_metadata_(&p, i++, /*copy=*/true)
        )
                return die_("priming our metadata");
 
-       if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
+       if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
                return die_("creating the encoded file");
 
        free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
@@ -594,7 +614,7 @@ static bool test_level_0_()
 
        printf("\n\n++++++ testing level 0 interface\n");
 
-       if(!generate_file_())
+       if(!generate_file_(/*include_cuesheet=*/true))
                return false;
 
        if(!test_file_(flacfile_, /*ignore_metadata=*/true))
@@ -651,6 +671,38 @@ static bool test_level_0_()
                printf("OK\n");
        }
 
+       {
+               printf("testing FLAC::Metadata::get_cuesheet(CueSheet *&)... ");
+
+               FLAC::Metadata::CueSheet *cuesheet = 0;
+
+               if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
+                       return die_("during FLAC::Metadata::get_cuesheet()");
+
+               /* check to see if some basic data matches (c.f. generate_file_()) */
+               if(cuesheet->get_lead_in() != 123)
+                       return die_("mismatch in cuesheet->get_lead_in()");
+
+               printf("OK\n");
+
+               delete cuesheet;
+       }
+
+       {
+               printf("testing FLAC::Metadata::get_cuesheet(CueSheet &)... ");
+
+               FLAC::Metadata::CueSheet cuesheet;
+
+               if(!FLAC::Metadata::get_cuesheet(flacfile_, cuesheet))
+                       return die_("during FLAC::Metadata::get_cuesheet()");
+
+               /* check to see if some basic data matches (c.f. generate_file_()) */
+               if(cuesheet.get_lead_in() != 123)
+                       return die_("mismatch in cuesheet.get_lead_in()");
+
+               printf("OK\n");
+       }
+
        if(!remove_file_(flacfile_))
                return false;
 
@@ -675,7 +727,7 @@ static bool test_level_1_()
        {
        printf("simple iterator on read-only file\n");
 
-       if(!generate_file_())
+       if(!generate_file_(/*include_cuesheet=*/false))
                return false;
 
        if(!change_stats_(flacfile_, /*read_only=*/true))
@@ -1340,7 +1392,7 @@ static bool test_level_2_(bool filename_based)
 
        printf("generate read-only file\n");
 
-       if(!generate_file_())
+       if(!generate_file_(/*include_cuesheet=*/false))
                return false;
 
        if(!change_stats_(flacfile_, /*read_only=*/true))
@@ -1895,7 +1947,7 @@ static bool test_level_2_misc_()
 
        printf("generate file\n");
 
-       if(!generate_file_())
+       if(!generate_file_(/*include_cuesheet=*/false))
                return false;
 
        printf("create chain\n");
index 4909844..57689d8 100644 (file)
@@ -478,10 +478,11 @@ static void decoder_error_callback_(const FLAC__FileDecoder *decoder, FLAC__Stre
        printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
 }
 
-static FLAC__bool generate_file_()
+static FLAC__bool generate_file_(FLAC__bool include_cuesheet)
 {
-       FLAC__StreamMetadata streaminfo, vorbiscomment, padding;
-       FLAC__StreamMetadata *metadata[1];
+       FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding;
+       FLAC__StreamMetadata *metadata[3];
+       unsigned i = 0, n = 0;
 
        printf("generating FLAC file for test\n");
 
@@ -513,20 +514,38 @@ static FLAC__bool generate_file_()
                vorbiscomment.data.vorbis_comment.comments = 0;
        }
 
+       {
+               if (0 == (cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)))
+                       return die_("priming our metadata");
+               cuesheet->is_last = false;
+               strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
+               cuesheet->data.cue_sheet.lead_in = 123;
+               cuesheet->data.cue_sheet.is_cd = false;
+               if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
+                       return die_("priming our metadata");
+               cuesheet->data.cue_sheet.tracks[0].number = 1;
+               if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
+                       return die_("priming our metadata");
+       }
+
        padding.is_last = true;
        padding.type = FLAC__METADATA_TYPE_PADDING;
        padding.length = 1234;
 
-       metadata[0] = &padding;
+       metadata[n++] = &vorbiscomment;
+       if (include_cuesheet)
+               metadata[n++] = cuesheet;
+       metadata[n++] = &padding;
 
        if(
-               !insert_to_our_metadata_(&streaminfo, 0, /*copy=*/true) ||
-               !insert_to_our_metadata_(&vorbiscomment, 1, /*copy=*/true) ||
-               !insert_to_our_metadata_(&padding, 2, /*copy=*/true)
+               !insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) ||
+               !insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) ||
+               (include_cuesheet && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
+               !insert_to_our_metadata_(&padding, i++, /*copy=*/true)
        )
                return die_("priming our metadata");
 
-       if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, 1))
+       if(!file_utils__generate_flacfile(flacfile_, 0, 512 * 1024, &streaminfo, metadata, n))
                return die_("creating the encoded file");
 
        free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
@@ -605,10 +624,11 @@ static FLAC__bool test_level_0_()
 {
        FLAC__StreamMetadata streaminfo;
        FLAC__StreamMetadata *tags = 0;
+       FLAC__StreamMetadata *cuesheet = 0;
 
        printf("\n\n++++++ testing level 0 interface\n");
 
-       if(!generate_file_())
+       if(!generate_file_(/*include_cuesheet=*/true))
                return false;
 
        if(!test_file_(flacfile_, decoder_metadata_callback_null_))
@@ -646,6 +666,19 @@ static FLAC__bool test_level_0_()
 
        FLAC__metadata_object_delete(tags);
 
+       printf("testing FLAC__metadata_get_cuesheet()... ");
+
+       if(!FLAC__metadata_get_cuesheet(flacfile_, &cuesheet))
+               return die_("during FLAC__metadata_get_cuesheet()");
+
+       /* check to see if some basic data matches (c.f. generate_file_()) */
+       if(cuesheet->data.cue_sheet.lead_in != 123)
+               return die_("mismatch in cuesheet->data.vorbis_comment.num_comments");
+
+       printf("OK\n");
+
+       FLAC__metadata_object_delete(cuesheet);
+
        if(!remove_file_(flacfile_))
                return false;
 
@@ -668,7 +701,7 @@ static FLAC__bool test_level_1_()
 
        printf("simple iterator on read-only file\n");
 
-       if(!generate_file_())
+       if(!generate_file_(/*include_cuesheet=*/false))
                return false;
 
        if(!change_stats_(flacfile_, /*read_only=*/true))
@@ -1327,7 +1360,7 @@ static FLAC__bool test_level_2_(FLAC__bool filename_based)
 
        printf("generate read-only file\n");
 
-       if(!generate_file_())
+       if(!generate_file_(/*include_cuesheet=*/false))
                return false;
 
        if(!change_stats_(flacfile_, /*read_only=*/true))
@@ -1840,7 +1873,7 @@ static FLAC__bool test_level_2_misc_()
 
        printf("generate file\n");
 
-       if(!generate_file_())
+       if(!generate_file_(/*include_cuesheet=*/false))
                return false;
 
        printf("create chain\n");