Commit 8e9c4519 authored by Josh Coalson's avatar Josh Coalson
Browse files

implement new CUESHEET metadata block

parent 5f34956e
......@@ -449,16 +449,19 @@ typedef enum {
/**< <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 @@ typedef struct {
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 @@ typedef struct {
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 FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_S
*/
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
......
......@@ -1231,7 +1231,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__Str
*/
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_delete_comment(FLAC__Str
*/
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 FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC
*/
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_find_entry_from(const FLAC__Str
*/
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_entry_matching(FLAC__Str
*/
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
......
......@@ -67,6 +67,22 @@ FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = 0xffff
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 @@ FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *se
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
......
......@@ -66,6 +66,23 @@ static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, co
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 @@ static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_
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 @@ static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__S
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 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type
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 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMet
}
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 @@ void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
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 @@ static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_V
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 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b
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_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *ob
{
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_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMet
FLAC__ASSERT(0 != object);
FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
FLAC__ASSERT(object->data.seek_table.num_points >= point_num);