</P>
<P>
+ <A NAME="flac_@@@@@@"><B>@@@@@@</B></A>
+ </P>
+ <P>
+ <UL>
+ <LI>
+ General:
+ <UL>
+ </UL>
+ </LI>
+ <LI>
+ FLAC format:
+ <UL>
+ </UL>
+ </LI>
+ <LI>
+ Ogg FLAC format:
+ <UL>
+ </UL>
+ </LI>
+ <LI>
+ flac:
+ <UL>
+ <LI>New option <A HREF="documentation.html#flac_options_input_size"><TT>--input-size</TT></A> to manually specify the input size when encoding raw samples from stdin.</LI>
+ </UL>
+ </LI>
+ <LI>
+ metaflac:
+ <UL>
+ </UL>
+ </LI>
+ <LI>
+ plugins:
+ <UL>
+ <LI>Added support for HTTP streaming in XMMS plugin.</LI>
+ </UL>
+ </LI>
+ <LI>
+ build system:
+ <UL>
+ </UL>
+ </LI>
+ <LI>
+ libraries:
+ <UL>
+ <LI>libFLAC, libOggFLAC: Can now be compiled to use only integer instructions, including encoding. The decoder is almost completely integer anyway but there were a couple places that needed a fixed-point replacement. There is no fixed-point version of LPC analysis yet, so if libFLAC is compiled integer-only, it will behave as if the max LPC order is 0 (i.e. used fixed predictors only).</LI>
+ </UL>
+ </LI>
+ <LI>
+ Interface changes:
+ <UL>
+ <LI>
+ libFLAC:
+ <UL>
+ <LI>Metadata interface now maintains a trailing NULL on Vorbis comment entries for convenience.</LI>
+ <LI><B>Added</B> FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair()</LI>
+ <LI><B>Added</B> FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair()</LI>
+ <LI><B>Changed</B> the signature of FLAC__metadata_object_vorbiscomment_entry_matches(): the first argument is now <TT>FLAC__StreamMetadata_VorbisComment_Entry entry</TT> (was <TT>const FLAC__StreamMetadata_VorbisComment_Entry *entry</TT>), i.e. <TT>entry</TT> is now pass-by-value.</LI>
+ </UL>
+ </LI>
+ <LI>
+ libFLAC++:
+ <UL>
+ <LI>Metadata interface now maintains a trailing NULL on Vorbis comment values for convenience.</LI>
+ <LI><B>Added</B> methods to FLAC::Metadata::VorbisComment::Entry for setting comment values from null-terminated strings:
+ <UL>
+ <LI>Entry(const char *field)</LI>
+ <LI>Entry(const char *field_name, const char *field_value)</LI>
+ <LI>bool set_field(const char *field)</LI>
+ <LI>bool set_field_value(const char *field_value)</LI>
+ </UL>
+ </LI>
+ </UL>
+ </LI>
+ <LI>
+ libOggFLAC:
+ <UL>
+ </UL>
+ </LI>
+ <LI>
+ libOggFLAC++:
+ <UL>
+ </UL>
+ </LI>
+ </UL>
+ </LI>
+ </UL>
+ </P>
+
+ <P>
<A NAME="flac_1_1_1"><B>FLAC 1.1.1</B></A>
</P>
<P>
* name is undefined; only the field value is relevant.
*
* A \a field as used in the methods refers to an
- * entire 'NAME=VALUE' string; the string is not null-
- * terminated and a length field is required since the
- * string may contain embedded nulls.
+ * entire 'NAME=VALUE' string; for convenience the
+ * string is null-terminated. A length field is
+ * required in the unlikely event that the value
+ * contains contain embedded nulls.
*
* A \a field_name is what is on the left side of the
* first '=' in the \a field. By definition it is ASCII
* A \a field_value is what is on the right side of the
* first '=' in the \a field. By definition, this may
* contain embedded nulls and so a \a field_value_length
- * is requires to describe it.
+ * is required to describe it. However in practice,
+ * embedded nulls are not known to be used, so it is
+ * generally safe to treat field values as null-
+ * terminated UTF-8 strings.
*
* Always check is_valid() after the constructor or operator=
* to make sure memory was properly allocated.
class FLACPP_API Entry {
public:
Entry();
+
Entry(const char *field, unsigned field_length);
+ Entry(const char *field); // assumes \a field is null-terminated
+
Entry(const char *field_name, const char *field_value, unsigned field_value_length);
+ Entry(const char *field_name, const char *field_value); // assumes \a field_value is null-terminated
+
Entry(const Entry &entry);
+
void operator=(const Entry &entry);
virtual ~Entry();
const char *get_field_value() const;
bool set_field(const char *field, unsigned field_length);
+ bool set_field(const char *field); // assumes \a field is null-terminated
bool set_field_name(const char *field_name);
bool set_field_value(const char *field_value, unsigned field_value_length);
+ bool set_field_value(const char *field_value); // assumes \a field_value is null-terminated
protected:
bool is_valid_;
::FLAC__StreamMetadata_VorbisComment_Entry entry_;
void clear_field_name();
void clear_field_value();
void construct(const char *field, unsigned field_length);
+ void construct(const char *field); // assumes \a field is null-terminated
void construct(const char *field_name, const char *field_value, unsigned field_value_length);
+ void construct(const char *field_name, const char *field_value); // assumes \a field_value is null-terminated
void compose_field();
void parse_field();
};
//! See FLAC__metadata_object_vorbiscomment_insert_comment()
bool insert_comment(unsigned index, const Entry &entry);
+ //! See FLAC__metadata_object_vorbiscomment_append_comment()
+ bool append_comment(const Entry &entry);
+
//! See FLAC__metadata_object_vorbiscomment_delete_comment()
bool delete_comment(unsigned index);
};
/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ *
+ * For convenience, the APIs maintain a trailing NUL character at the end of
+ * \a entry which is not counted toward \a length or stored in the stream,
+ * i.e.
+ * \code strlen(entry) == length \endcode
+ *
+ * It's recommended but not required for users to follow this convention as
+ * well when dealing directly with FLAC__StreamMetadata_VorbisComment_Entry
+ * as it makes dealing with plain strings easier.
*/
typedef struct {
FLAC__uint32 length;
* FLAC__metadata_object_application_set_data(), you will get an assertion
* failure.
*
+ * The FLAC__metadata_object_vorbiscomment_*() functions for convenience
+ * maintain a trailing NUL on each Vorbis comment entry. This is not counted
+ * toward the length or stored in the stream, but it can make working with plain
+ * comments (those that don't contain embedded-NULs in the value) easier.
+ * Entries passed into these functions have trailing NULs added if missing, and
+ * returned entries are guaranteed to have a trailing NUL.
+ *
* There is no need to recalculate the length field on metadata blocks you
* have modified. They will be calculated automatically before they are
* written back to a file.
/** Sets the application data of an APPLICATION block.
*
* If \a copy is \c true, a copy of the data is stored; otherwise, the object
- * takes ownership of the pointer. Returns \c false if \a copy == \c true
- * and malloc fails.
+ * takes ownership of the pointer.
*
* \param object A pointer to an existing APPLICATION object.
* \param data A pointer to the data to set.
* \code (data != NULL && length > 0) ||
* (data == NULL && length == 0 && copy == false) \endcode
* \retval FLAC__bool
- * \c false if \a copy is \c true and malloc fails, else \c true.
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy);
* \code object != NULL \endcode
* \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
* \retval FLAC__bool
- * \c false if realloc fails, else \c true.
+ * \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact);
/** Sets the vendor string in a VORBIS_COMMENT block.
*
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
* If \a copy is \c true, a copy of the entry is stored; otherwise, the object
- * takes ownership of the \c entry->entry pointer. Returns \c false if
- * \a copy == \c true and malloc fails.
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
*
* \param object A pointer to an existing VORBIS_COMMENT object.
* \param entry The entry to set the vendor string to.
* \assert
* \code object != NULL \endcode
* \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
- * \code (entry->entry != NULL && entry->length > 0) ||
- * (entry->entry == NULL && entry->length == 0) \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
* \retval FLAC__bool
- * \c false if \a copy is \c true and malloc fails, else \c true.
+ * \c false if memory allocation fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
/** Sets a comment in a VORBIS_COMMENT block.
*
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
* If \a copy is \c true, a copy of the entry is stored; otherwise, the object
- * takes ownership of the \c entry->entry pointer. Returns \c false if
- * \a copy == \c true and malloc fails.
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
*
* \param object A pointer to an existing VORBIS_COMMENT object.
* \param comment_num Index into comment array to set.
* \code object != NULL \endcode
* \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
* \code comment_num < object->data.vorbis_comment.num_comments \endcode
- * \code (entry->entry != NULL && entry->length > 0) ||
- * (entry->entry == NULL && entry->length == 0) \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
* \retval FLAC__bool
- * \c false if \a copy is \c true and malloc fails, else \c true.
+ * \c false if memory allocation fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
/** Insert a comment in a VORBIS_COMMENT block at the given index.
*
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
* If \a copy is \c true, a copy of the entry is stored; otherwise, the object
- * takes ownership of the \c entry->entry pointer. Returns \c false if
- * \a copy == \c true and malloc fails.
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
*
* \param object A pointer to an existing VORBIS_COMMENT object.
* \param comment_num The index at which to insert the comment. The comments
* \code object != NULL \endcode
* \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
* \code object->data.vorbis_comment.num_comments >= comment_num \endcode
- * \code (entry->entry != NULL && entry->length > 0) ||
- * (entry->entry == NULL && entry->length == 0 && copy == false) \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
* \retval FLAC__bool
- * \c false if \a copy is \c true and malloc fails, else \c true.
+ * \c false if memory allocation fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+/** Appends a comment to a VORBIS_COMMENT block.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param entry The comment to insert.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Replaces comments in a VORBIS_COMMENT block with a new one.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * Depending on the the value of \a all, either all or just the first comment
+ * whose field name(s) match the given entry's name will be replaced by the
+ * given entry. If no comments match, \a entry will simply be appended.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param entry The comment to insert.
+ * \param all If \c true, all comments whose field name matches
+ * \a entry's field name will be removed, and \a entry will
+ * be inserted at the position of the first matching
+ * comment. If \c false, only the first comment whose
+ * field name matches \a entry's field name will be
+ * replaced with \a entry.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy);
+
/** Delete a comment in a VORBIS_COMMENT block at the given index.
*
* \param object A pointer to an existing VORBIS_COMMENT object.
* \code object != NULL \endcode
* \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
* \code object->data.vorbis_comment.num_comments > comment_num \endcode
- * \code (entry->entry != NULL && entry->length > 0) ||
- * (entry->entry == NULL && entry->length == 0 && copy == false) \endcode
* \retval FLAC__bool
- * \c false if realloc fails, else \c true.
+ * \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
-/*@@@@ add to unit tests */
+/** Creates a Vorbis comment entry from NUL-terminated name and value strings.
+ *
+ * On return, the filled-in \a entry->entry pointer will point to malloc()ed
+ * memory and shall be owned by the caller. For convenience the entry will
+ * have a terminating NUL.
+ *
+ * \param entry A pointer to a Vorbis comment entry. The entry's
+ * \c entry pointer should not point to allocated
+ * memory as it will be overwritten.
+ * \param field_name The field name in ASCII, \c NULL terminated.
+ * \param field_value The field value in UTF-8, \c NULL terminated.
+ * \assert
+ * \code entry != NULL \endcode
+ * \code field_name != NULL \endcode
+ * \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value);
+
+/** Splits a Vorbis comment entry into NUL-terminated name and value strings.
+ *
+ * The returned pointers to name and value will be allocated by malloc()
+ * and shall be owned by the caller.
+ *
+ * \param entry A pointer to an existing Vorbis comment entry.
+ * \param field_name The address of where the returned pointer to the
+ * field name will be stored.
+ * \param field_value The address of where the returned pointer to the
+ * field value will be stored.
+ * \assert
+ * \code (entry.entry != NULL && entry.length > 0) \endcode
+ * \code memchr(entry.entry, '=', entry.length) != NULL \endcode
+ * \code field_name != NULL \endcode
+ * \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value);
+
/** Check if the given Vorbis comment entry's field name matches the given
* field name.
*
* \param field_name_length The length of \a field_name, not including the
* terminating \c NULL.
* \assert
- * \code entry != NULL \endcode
- * \code (entry->entry != NULL && entry->length > 0) \endcode
+ * \code (entry.entry != NULL && entry.length > 0) \endcode
* \retval FLAC__bool
* \c true if the field names match, else \c false
*/
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, unsigned field_name_length);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length);
-/*@@@@ add to unit tests */
/** Find a Vorbis comment with the given field name.
*
* The search begins at entry number \a offset; use an offset of 0 to
* \assert
* \code object != NULL \endcode
* \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code field_name != NULL \endcode
* \retval int
* The offset in the comment array of the first comment whose field
* name matches \a field_name, or \c -1 if no match was found.
*/
FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
-/*@@@@ add to unit tests */
/** Remove first Vorbis comment matching the given field name.
*
* \param object A pointer to an existing VORBIS_COMMENT object.
*/
FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name);
-/*@@@@ add to unit tests */
/** Remove all Vorbis comments matching the given field name.
*
* \param object A pointer to an existing VORBIS_COMMENT object.
* \code object->data.cue_sheet.num_tracks > track_num \endcode
* \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
* \retval FLAC__bool
- * \c false if realloc fails, else \c true.
+ * \c false if realloc() fails, else \c 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);
* \code object->data.cue_sheet.num_tracks > track_num \endcode
* \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
* \retval FLAC__bool
- * \c false if realloc fails, else \c true.
+ * \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
* \code object->data.cue_sheet.num_tracks > track_num \endcode
* \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode
* \retval FLAC__bool
- * \c false if realloc fails, else \c true.
+ * \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
/** Sets a track in a CUESHEET block.
*
* If \a copy is \c true, a copy of the track is stored; otherwise, the object
- * takes ownership of the \a track pointer. Returns \c false if
- * \a copy == \c true and malloc fails.
+ * takes ownership of the \a track pointer.
*
* \param object A pointer to an existing CUESHEET object.
* \param track_num Index into track array to set. NOTE: this is not
* \code (track->indices != NULL && track->num_indices > 0) ||
* (track->indices == NULL && track->num_indices == 0)
* \retval FLAC__bool
- * \c false if \a copy is \c true and malloc fails, else \c true.
+ * \c false if \a copy is \c true and malloc() fails, else \c 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);
/** Insert a track in a CUESHEET block at the given index.
*
* If \a copy is \c true, a copy of the track is stored; otherwise, the object
- * takes ownership of the \a track pointer. Returns \c false if
- * \a copy == \c true and malloc fails.
+ * takes ownership of the \a track pointer.
*
* \param object A pointer to an existing CUESHEET object.
* \param track_num The index at which to insert the track. NOTE: this
* \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
* \code object->data.cue_sheet.num_tracks >= track_num \endcode
* \retval FLAC__bool
- * \c false if \a copy is \c true and malloc fails, else \c true.
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
* \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
* \code object->data.cue_sheet.num_tracks >= track_num \endcode
* \retval FLAC__bool
- * \c false if \a copy is \c true and malloc fails, else \c true.
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num);
* \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
* \code object->data.cue_sheet.num_tracks > track_num \endcode
* \retval FLAC__bool
- * \c false if realloc fails, else \c true.
+ * \c false if realloc() fails, else \c true.
*/
FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
entry.length = strlen((const char *)entry.entry);
- if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, block->data.vorbis_comment.num_comments, entry, /*copy=*/true)) {
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
if(needs_free)
free(converted);
*violation = "memory allocation failure";
construct(field, field_length);
}
+ VorbisComment::Entry::Entry(const char *field)
+ {
+ zero();
+ construct(field);
+ }
+
VorbisComment::Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)
{
zero();
construct(field_name, field_value, field_value_length);
}
+ VorbisComment::Entry::Entry(const char *field_name, const char *field_value)
+ {
+ zero();
+ construct(field_name, field_value);
+ }
+
VorbisComment::Entry::Entry(const Entry &entry)
{
FLAC__ASSERT(entry.is_valid());
clear_entry();
- if(0 == (entry_.entry = (FLAC__byte*)malloc(field_length))) {
+ if(0 == (entry_.entry = (FLAC__byte*)malloc(field_length+1))) {
is_valid_ = false;
}
else {
entry_.length = field_length;
memcpy(entry_.entry, field, field_length);
+ entry_.entry[field_length] = '\0';
(void) parse_field();
}
return is_valid_;
}
+ bool VorbisComment::Entry::set_field(const char *field)
+ {
+ return set_field(field, strlen(field));
+ }
+
bool VorbisComment::Entry::set_field_name(const char *field_name)
{
FLAC__ASSERT(is_valid());
clear_field_value();
- if(0 == (field_value_ = (char *)malloc(field_value_length))) {
+ if(0 == (field_value_ = (char *)malloc(field_value_length+1))) {
is_valid_ = false;
}
else {
field_value_length_ = field_value_length;
memcpy(field_value_, field_value, field_value_length);
+ field_value_[field_value_length] = '\0';
compose_field();
}
return is_valid_;
}
+ bool VorbisComment::Entry::set_field_value(const char *field_value)
+ {
+ return set_field_value(field_value, strlen(field_value));
+ }
+
void VorbisComment::Entry::zero()
{
is_valid_ = true;
parse_field();
}
+ void VorbisComment::Entry::construct(const char *field)
+ {
+ construct(field, strlen(field));
+ }
+
void VorbisComment::Entry::construct(const char *field_name, const char *field_value, unsigned field_value_length)
{
if(set_field_name(field_name) && set_field_value(field_value, field_value_length))
compose_field();
}
+ void VorbisComment::Entry::construct(const char *field_name, const char *field_value)
+ {
+ construct(field_name, field_value, strlen(field_value));
+ }
+
void VorbisComment::Entry::compose_field()
{
clear_entry();
- if(0 == (entry_.entry = (FLAC__byte*)malloc(field_name_length_ + 1 + field_value_length_))) {
+ if(0 == (entry_.entry = (FLAC__byte*)malloc(field_name_length_ + 1 + field_value_length_ + 1))) {
is_valid_ = false;
}
else {
entry_.length += 1;
memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
entry_.length += field_value_length_;
+ entry_.entry[entry_.length] = '\0';
is_valid_ = true;
}
}
}
else {
field_value_length_ = entry_.length - field_name_length_ - 1;
- if(0 == (field_value_ = (char *)malloc(field_value_length_))) {
+ if(0 == (field_value_ = (char *)malloc(field_value_length_ + 1))) { // +1 for the trailing \0
is_valid_ = false;
return;
}
memcpy(field_value_, ++p, field_value_length_);
+ field_value_[field_value_length_] = '\0';
}
is_valid_ = true;
return (bool)::FLAC__metadata_object_vorbiscomment_insert_comment(object_, index, entry.get_entry(), /*copy=*/true);
}
+ bool VorbisComment::append_comment(const VorbisComment::Entry &entry)
+ {
+ FLAC__ASSERT(is_valid());
+ return (bool)::FLAC__metadata_object_vorbiscomment_append_comment(object_, entry.get_entry(), /*copy=*/true);
+ }
+
bool VorbisComment::delete_comment(unsigned index)
{
FLAC__ASSERT(is_valid());
entry->entry = 0;
}
else {
- if(0 == (entry->entry = (FLAC__byte*)malloc(entry->length)))
+ if(0 == (entry->entry = (FLAC__byte*)malloc(entry->length+1)))
return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
if(read_cb(entry->entry, 1, entry->length, handle) != entry->length)
return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ entry->entry[entry->length] = '\0';
}
return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
return true;
}
+static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length)
+{
+ FLAC__byte *x = (FLAC__byte*)realloc(*entry, length+1);
+ if(0 != x) {
+ x[length] = '\0';
+ *entry = x;
+ return true;
+ }
+ else
+ return false;
+}
+
static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
{
to->length = from->length;
else {
FLAC__byte *x;
FLAC__ASSERT(from->length > 0);
- if(0 == (x = (FLAC__byte*)malloc(from->length)))
+ if(0 == (x = (FLAC__byte*)malloc(from->length+1)))
return false;
memcpy(x, from->entry, from->length);
+ x[from->length] = '\0';
to->entry = x;
}
return true;
save = dest->entry;
- /* do the copy first so that if we fail we leave the object untouched */
- if(copy && (0 != src->entry && src->length > 0)) {
- if(!copy_vcentry_(dest, src))
- return false;
+ if(0 != src->entry && src->length > 0) {
+ if(copy) {
+ /* do the copy first so that if we fail we leave the dest object untouched */
+ if(!copy_vcentry_(dest, src))
+ return false;
+ }
+ else {
+ /* we have to make sure that the string we're taking over is null-terminated */
+
+ /*
+ * Stripping the const from src->entry is OK since we're taking
+ * ownership of the pointer. This is a hack around a deficiency
+ * in the API where the same function is used for 'copy' and
+ * 'own', but the source entry is a const pointer. If we were
+ * precise, the 'own' flavor would be a separate function with a
+ * non-const source pointer. But it's not, so we hack away.
+ */
+ if(!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length))
+ return false;
+ *dest = *src;
+ }
}
else {
- /* either we're not copying or the src is null */
+ /* the src is null */
*dest = *src;
}
return true;
}
+static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name, unsigned field_name_length)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT(0 != field_name);
+
+ for(i = offset; i < object->data.vorbis_comment.num_comments; i++) {
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length))
+ return (int)i;
+ }
+
+ return -1;
+}
+
static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
{
unsigned i;
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
{
object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
- if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length)) {
+ if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
free(object);
return 0;
}
return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
}
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy)
+{
+ FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+ {
+ int i;
+ unsigned field_name_length;
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+
+ FLAC__ASSERT(0 != eq);
+
+ if(0 == eq)
+ return false; /* double protection */
+
+ field_name_length = eq-entry.entry;
+
+ if((i = vorbiscomment_find_entry_from_(object, 0, entry.entry, field_name_length)) >= 0) {
+ unsigned index = (unsigned)i;
+ if(!FLAC__metadata_object_vorbiscomment_set_comment(object, index, entry, copy))
+ return false;
+ if(all && (index+1 < object->data.vorbis_comment.num_comments)) {
+ for(i = vorbiscomment_find_entry_from_(object, index+1, entry.entry, field_name_length); i >= 0; ) {
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i))
+ return false;
+ if((unsigned)i < object->data.vorbis_comment.num_comments)
+ i = vorbiscomment_find_entry_from_(object, (unsigned)i, entry.entry, field_name_length);
+ else
+ i = -1;
+ }
+ }
+ return true;
+ }
+ else
+ return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy);
+ }
+}
+
FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num)
{
FLAC__StreamMetadata_VorbisComment *vc;
return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
}
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, unsigned field_name_length)
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
{
- const FLAC__byte *eq = (FLAC__byte*)memchr(entry->entry, '=', entry->length);
+ FLAC__ASSERT(0 != entry);
+ FLAC__ASSERT(0 != field_name);
+ FLAC__ASSERT(0 != field_value);
+
+ {
+ const size_t nn = strlen(field_name);
+ const size_t nv = strlen(field_value);
+ entry->length = nn + 1 /*=*/ + nv;
+ if(0 == (entry->entry = malloc(entry->length+1)))
+ return false;
+ memcpy(entry->entry, field_name, nn);
+ entry->entry[nn] = '=';
+ memcpy(entry->entry+nn+1, field_value, nv);
+ entry->entry[entry->length] = '\0';
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
+{
+ FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+ FLAC__ASSERT(0 != field_name);
+ FLAC__ASSERT(0 != field_value);
+ {
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+ const size_t nn = eq-entry.entry;
+ const size_t nv = entry.length-nn-1; /* -1 for the '=' */
+ FLAC__ASSERT(0 != eq);
+ if(0 == eq)
+ return false; /* double protection */
+ if(0 == (*field_name = malloc(nn+1)))
+ return false;
+ if(0 == (*field_value = malloc(nv+1))) {
+ free(*field_name);
+ return false;
+ }
+ memcpy(*field_name, entry.entry, nn);
+ memcpy(*field_value, entry.entry+nn+1, nv);
+ (*field_name)[nn] = '\0';
+ (*field_value)[nv] = '\0';
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length)
+{
+ FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+ {
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
#if defined _MSC_VER || defined __MINGW32__
#define FLAC__STRNCASECMP strnicmp
#else
#define FLAC__STRNCASECMP strncasecmp
#endif
- return (0 != eq && (unsigned)(eq-entry->entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry->entry, field_name_length));
+ return (0 != eq && (unsigned)(eq-entry.entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length));
#undef FLAC__STRNCASECMP
+ }
}
FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
{
- const unsigned field_name_length = strlen(field_name);
- unsigned i;
+ FLAC__ASSERT(0 != field_name);
- FLAC__ASSERT(0 != object);
- FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
- for(i = offset; i < object->data.vorbis_comment.num_comments; i++) {
- if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length))
- return (int)i;
- }
-
- return -1;
+ return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name));
}
FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
- if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length)) {
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
return -1;
else
/* must delete from end to start otherwise it will interfere with our iteration */
for(i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
- if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments + i, field_name, field_name_length)) {
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
matching++;
ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i);
}
if(!FLAC__bitbuffer_read_raw_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length, read_callback_, decoder))
return false; /* the read_callback_ sets the state for us */
if(obj->vendor_string.length > 0) {
- if(0 == (obj->vendor_string.entry = (FLAC__byte*)malloc(obj->vendor_string.length))) {
+ if(0 == (obj->vendor_string.entry = (FLAC__byte*)malloc(obj->vendor_string.length+1))) {
decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
return false;
}
if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length, read_callback_, decoder))
return false; /* the read_callback_ sets the state for us */
+ obj->vendor_string.entry[obj->vendor_string.length] = '\0';
}
else
obj->vendor_string.entry = 0;
if(!FLAC__bitbuffer_read_raw_uint32_little_endian(decoder->private_->input, &obj->comments[i].length, read_callback_, decoder))
return false; /* the read_callback_ sets the state for us */
if(obj->comments[i].length > 0) {
- if(0 == (obj->comments[i].entry = (FLAC__byte*)malloc(obj->comments[i].length))) {
+ if(0 == (obj->comments[i].entry = (FLAC__byte*)malloc(obj->comments[i].length+1))) {
decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
return false;
}
if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length, read_callback_, decoder))
return false; /* the read_callback_ sets the state for us */
+ obj->comments[i].entry[obj->comments[i].length] = '\0';
}
else
obj->comments[i].entry = 0;
entry.length = strlen((const char *)entry.entry);
- if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, block->data.vorbis_comment.num_comments, entry, /*copy=*/true)) {
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
if(needs_free)
free(converted);
fprintf(stderr, "%s: ERROR: memory allocation failure\n", filename);
if(!raw) {
/*
- * utf8_decode() works on NULL-terminated strings, so
- * we append a null to the entry. @@@ Note, this means
- * that comments that contain an embedded null will be
- * truncated by utf_decode().
+ * WATCHOUT: comments that contain an embedded null will
+ * be truncated by utf_decode().
*/
- char *terminated, *converted;
+ char *converted;
- if(0 == (terminated = malloc(entry->length + 1)))
- die("out of memory allocating space for vorbis comment");
- memcpy(terminated, entry->entry, entry->length);
- terminated[entry->length] = '\0';
- if(utf8_decode(terminated, &converted) >= 0) {
+ if(utf8_decode(entry->entry, &converted) >= 0) {
(void) local_fwrite(converted, 1, strlen(converted), f);
- free(terminated);
free(converted);
}
else {
- free(terminated);
(void) local_fwrite(entry->entry, 1, entry->length, f);
}
}
}
}
- fprintf(f, "\n");
+ putc('\n', f);
}
void write_vc_fields(const char *filename, const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry entry[], unsigned num_entries, FLAC__bool raw, FILE *f)
const unsigned field_name_length = (0 != field_name)? strlen(field_name) : 0;
for(i = 0; i < num_entries; i++) {
- if(0 == field_name || FLAC__metadata_object_vorbiscomment_entry_matches(entry + i, field_name, field_name_length))
+ if(0 == field_name || FLAC__metadata_object_vorbiscomment_entry_matches(entry[i], field_name, field_name_length))
write_vc_field(filename, entry + i, raw, f);
}
}
entry.entry = (FLAC__byte *)buffer;
entry.length = strlen(buffer);
- return FLAC__metadata_object_vorbiscomment_insert_comment(block, block->data.vorbis_comment.num_comments, entry, /*copy=*/true);
+ return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true);
}
FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency)
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);
- memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
+ vorbiscomment.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+ memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
vorbiscomment.data.vorbis_comment.num_comments = 0;
vorbiscomment.data.vorbis_comment.comments = 0;
}
vorbiscomment_.type = ::FLAC__METADATA_TYPE_VORBIS_COMMENT;
vorbiscomment_.length = (4 + 5) + 4 + (4 + 12) + (4 + 12);
vorbiscomment_.data.vorbis_comment.vendor_string.length = 5;
- vorbiscomment_.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(5);
- memcpy(vorbiscomment_.data.vorbis_comment.vendor_string.entry, "name0", 5);
+ vorbiscomment_.data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(5+1);
+ memcpy(vorbiscomment_.data.vorbis_comment.vendor_string.entry, "name0", 5+1);
vorbiscomment_.data.vorbis_comment.num_comments = 2;
vorbiscomment_.data.vorbis_comment.comments = (::FLAC__StreamMetadata_VorbisComment_Entry*)malloc_or_die_(vorbiscomment_.data.vorbis_comment.num_comments * sizeof(::FLAC__StreamMetadata_VorbisComment_Entry));
vorbiscomment_.data.vorbis_comment.comments[0].length = 12;
- vorbiscomment_.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(12);
- memcpy(vorbiscomment_.data.vorbis_comment.comments[0].entry, "name2=value2", 12);
+ vorbiscomment_.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(12+1);
+ memcpy(vorbiscomment_.data.vorbis_comment.comments[0].entry, "name2=value2", 12+1);
vorbiscomment_.data.vorbis_comment.comments[1].length = 12;
- vorbiscomment_.data.vorbis_comment.comments[1].entry = (FLAC__byte*)malloc_or_die_(12);
- memcpy(vorbiscomment_.data.vorbis_comment.comments[1].entry, "name3=value3", 12);
+ vorbiscomment_.data.vorbis_comment.comments[1].entry = (FLAC__byte*)malloc_or_die_(12+1);
+ memcpy(vorbiscomment_.data.vorbis_comment.comments[1].entry, "name3=value3", 12+1);
cuesheet_.is_last = true;
cuesheet_.type = ::FLAC__METADATA_TYPE_CUESHEET;
return die_("!is_valid()");
printf("OK\n");
+ {
+ printf("testing Entry::Entry(const char *field)... ");
+ FLAC::Metadata::VorbisComment::Entry entry2z("name2=value2");
+ if(!entry2z.is_valid())
+ return die_("!is_valid()");
+ if(strcmp(entry2.get_field(), entry2z.get_field()))
+ return die_("bad value");
+ printf("OK\n");
+ }
+
printf("testing Entry::Entry(const char *field_name, const char *field_value, unsigned field_value_length)... ");
FLAC::Metadata::VorbisComment::Entry entry3("name3", "value3", strlen("value3"));
if(!entry3.is_valid())
return die_("!is_valid()");
printf("OK\n");
+ {
+ printf("testing Entry::Entry(const char *field_name, const char *field_value)... ");
+ FLAC::Metadata::VorbisComment::Entry entry3z("name3", "value3");
+ if(!entry3z.is_valid())
+ return die_("!is_valid()");
+ if(strcmp(entry3.get_field(), entry3z.get_field()))
+ return die_("bad value");
+ printf("OK\n");
+ }
+
printf("testing Entry::Entry(const Entry &entry)... ");
{
FLAC::Metadata::VorbisComment::Entry entry2copy(entry2);
return die_("entry mismatch");
printf("OK\n");
- printf("testing Entry::set_field_value()... ");
+ printf("testing Entry::set_field_value(const char *field_value, unsigned field_value_length)... ");
if(!entry1.set_field_value("value1", strlen("value1")))
return die_("returned false");
if(0 != memcmp(entry1.get_field_value(), "value1", strlen("value1")))
return die_("entry mismatch");
printf("OK\n");
- printf("testing Entry::set_field()... ");
+ printf("testing Entry::set_field_value(const char *field_value)... ");
+ if(!entry1.set_field_value("value1"))
+ return die_("returned false");
+ if(0 != memcmp(entry1.get_field_value(), "value1", strlen("value1")))
+ return die_("value mismatch");
+ if(0 != memcmp(entry1.get_field(), "name1=value1", strlen("name1=value1")))
+ return die_("entry mismatch");
+ printf("OK\n");
+
+ printf("testing Entry::set_field(const char *field, unsigned field_length)... ");
if(!entry1.set_field("name0=value0", strlen("name0=value0")))
return die_("returned false");
if(0 != memcmp(entry1.get_field_name(), "name0", strlen("name0")))
return die_("entry mismatch");
printf("OK\n");
+ printf("testing Entry::set_field(const char *field)... ");
+ if(!entry1.set_field("name0=value0"))
+ return die_("returned false");
+ if(0 != memcmp(entry1.get_field_name(), "name0", strlen("name0")))
+ return die_("value mismatch");
+ if(0 != memcmp(entry1.get_field_value(), "value0", strlen("value0")))
+ return die_("value mismatch");
+ if(0 != memcmp(entry1.get_field(), "name0=value0", strlen("name0=value0")))
+ return die_("entry mismatch");
+ printf("OK\n");
+
printf("PASSED\n\n");
return die_("value mismatch");
printf("OK\n");
+ printf("testing VorbisComment::append_comment()... +\n");
+ printf(" VorbisComment::get_comment()... ");
+ if(!block.append_comment(entry3))
+ return die_("returned false");
+ if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[1].length)
+ return die_("length mismatch");
+ if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[1].entry, vorbiscomment_.data.vorbis_comment.comments[1].length))
+ return die_("value mismatch");
+ printf("OK\n");
+
+ printf("testing VorbisComment::append_comment()... +\n");
+ printf(" VorbisComment::get_comment()... ");
+ if(!block.append_comment(entry2))
+ return die_("returned false");
+ if(block.get_comment(1).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+ return die_("length mismatch");
+ if(0 != memcmp(block.get_comment(1).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+ return die_("value mismatch");
+ printf("OK\n");
+
+ printf("testing VorbisComment::delete_comment()... +\n");
+ printf(" VorbisComment::get_comment()... ");
+ if(!block.delete_comment(0))
+ return die_("returned false");
+ if(block.get_comment(0).get_field_length() != vorbiscomment_.data.vorbis_comment.comments[0].length)
+ return die_("length[0] mismatch");
+ if(0 != memcmp(block.get_comment(0).get_field(), vorbiscomment_.data.vorbis_comment.comments[0].entry, vorbiscomment_.data.vorbis_comment.comments[0].length))
+ return die_("value[0] mismatch");
+ printf("OK\n");
+
+ printf("testing VorbisComment::delete_comment()... +\n");
+ printf(" VorbisComment::get_comment()... ");
+ if(!block.delete_comment(0))
+ return die_("returned false");
+ if(block.get_num_comments() != 0)
+ return die_("block mismatch, expected num_comments = 0");
+ printf("OK\n");
+
printf("testing VorbisComment::insert_comment()... +\n");
printf(" VorbisComment::get_comment()... ");
if(!block.insert_comment(0, entry3))
vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0);
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);
- memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
+ vorbiscomment->data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+ memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
vorbiscomment->data.vorbis_comment.num_comments = 2;
vorbiscomment->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)malloc_or_die_(vorbiscomment->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
vorbiscomment->data.vorbis_comment.comments[0].length = 5;
- vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5);
- memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5);
+ vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5+1);
+ memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1);
vorbiscomment->data.vorbis_comment.comments[1].length = 0;
vorbiscomment->data.vorbis_comment.comments[1].entry = 0;
}
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 = malloc_or_die_(vendor_string_length);
- memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
+ vorbiscomment.data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1);
+ memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
vorbiscomment.data.vorbis_comment.num_comments = 0;
vorbiscomment.data.vorbis_comment.comments = 0;
}
static void entry_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field)
{
entry->length = strlen(field);
- entry->entry = (FLAC__byte*)malloc(entry->length);
+ entry->entry = (FLAC__byte*)malloc(entry->length+1);
FLAC__ASSERT(0 != entry->entry);
memcpy(entry->entry, field, entry->length);
+ entry->entry[entry->length] = '\0';
}
static void entry_clone_(FLAC__StreamMetadata_VorbisComment_Entry *entry)
{
- FLAC__byte *x = (FLAC__byte*)malloc(entry->length);
+ FLAC__byte *x = (FLAC__byte*)malloc(entry->length+1);
FLAC__ASSERT(0 != x);
memcpy(x, entry->entry, entry->length);
+ x[entry->length] = '\0';
entry->entry = x;
}
vc_calc_len_(block);
}
+static int vc_find_from_(FLAC__StreamMetadata *block, const char *name, unsigned start)
+{
+ const unsigned n = strlen(name);
+ unsigned i;
+ for(i = start; i < block->data.vorbis_comment.num_comments; i++) {
+ const FLAC__StreamMetadata_VorbisComment_Entry *entry = &block->data.vorbis_comment.comments[i];
+ if(entry->length > n && 0 == strncmp(entry->entry, name, n) && entry->entry[n] == '=')
+ return (int)i;
+ }
+ return -1;
+}
+
static void vc_set_vs_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field)
{
if(0 != block->data.vorbis_comment.vendor_string.entry)
vc_calc_len_(block);
}
+static void vc_replace_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field, FLAC__bool all)
+{
+ int index;
+ char field_name[256];
+ const char *eq = strchr(field, '=');
+ FLAC__ASSERT(eq>field && (unsigned)(eq-field) < sizeof(field_name));
+ memcpy(field_name, field, eq-field);
+ field_name[eq-field]='\0';
+
+ index = vc_find_from_(block, field_name, 0);
+ if(index < 0)
+ vc_insert_new_(entry, block, block->data.vorbis_comment.num_comments, field);
+ else {
+ vc_set_new_(entry, block, (unsigned)index, field);
+ if(all) {
+ for(index = index+1; index >= 0 && (unsigned)index < block->data.vorbis_comment.num_comments; )
+ if((index = vc_find_from_(block, field_name, (unsigned)index)) >= 0)
+ vc_delete_(block, (unsigned)index);
+ }
+ }
+
+ 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;
FLAC__StreamMetadata_CueSheet_Index index;
FLAC__StreamMetadata_CueSheet_Track track;
unsigned i, expected_length, seekpoints;
+ int j;
static FLAC__byte dummydata[4] = { 'a', 'b', 'c', 'd' };
printf("\n+++ libFLAC unit test: metadata objects\n\n");
printf("testing VORBIS_COMMENT\n");
+ {
+ FLAC__StreamMetadata_VorbisComment_Entry entry_;
+ char *field_name, *field_value;
+
+ printf("testing FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair()... ");
+ if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry_, "name", "value")) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(strcmp(entry_.entry, "name=value")) {
+ printf("FAILED, field mismatch\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair()... ");
+ if(!FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(entry_, &field_name, &field_value)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(strcmp(field_name, "name")) {
+ printf("FAILED, field name mismatch\n");
+ return false;
+ }
+ if(strcmp(field_value, "value")) {
+ printf("FAILED, field value mismatch\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... ");
+ if(!FLAC__metadata_object_vorbiscomment_entry_matches(entry_, field_name, strlen(field_name))) {
+ printf("FAILED, expected true, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... ");
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(entry_, "blah", strlen("blah"))) {
+ printf("FAILED, expected false, returned true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ free(entry_.entry);
+ free(field_name);
+ free(field_value);
+ }
+
printf("testing FLAC__metadata_object_new()... ");
block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
if(0 == block) {
return false;
printf("OK\n");
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ vc_resize_(vorbiscomment, 0);
+ printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+ if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on empty array...");
vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) {
return false;
printf("OK\n");
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1");
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1");
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name3")) != 1) {
+ printf("FAILED, expected 1, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 4) {
+ printf("FAILED, expected 4, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 5) {
+ printf("FAILED, expected 5, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name2")) != 0) {
+ printf("FAILED, expected 0, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name2")) != -1) {
+ printf("FAILED, expected -1, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "blah")) != -1) {
+ printf("FAILED, expected -1, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, copy)...");
+ vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false);
+ if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ if(block->data.vorbis_comment.num_comments != 6) {
+ printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, copy)...");
+ vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true);
+ if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ if(block->data.vorbis_comment.num_comments != 4) {
+ printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ printf("OK\n");
+
printf("testing FLAC__metadata_object_clone()... ");
blockcopy = FLAC__metadata_object_clone(block);
if(0 == blockcopy) {
return false;
printf("OK\n");
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 1, "rem0=val0");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 2, "rem0=val1");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 3, "rem0=val2");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"blah\")...");
+ if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "blah")) != 0) {
+ printf("FAILED, expected 0, got %d\n", j);
+ return false;
+ }
+ if(block->data.vorbis_comment.num_comments != 4) {
+ printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"rem0\")...");
+ vc_delete_(vorbiscomment, 1);
+ if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "rem0")) != 1) {
+ printf("FAILED, expected 1, got %d\n", j);
+ return false;
+ }
+ if(block->data.vorbis_comment.num_comments != 3) {
+ printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"blah\")...");
+ if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "blah")) != 0) {
+ printf("FAILED, expected 0, got %d\n", j);
+ return false;
+ }
+ if(block->data.vorbis_comment.num_comments != 3) {
+ printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"rem0\")...");
+ vc_delete_(vorbiscomment, 1);
+ vc_delete_(vorbiscomment, 1);
+ if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "rem0")) != 2) {
+ printf("FAILED, expected 2, got %d\n", j);
+ return false;
+ }
+ if(block->data.vorbis_comment.num_comments != 1) {
+ printf("FAILED, expected 1 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
printf("testing FLAC__metadata_object_vorbiscomment_set_comment(copy)...");
vc_set_new_(&entry, vorbiscomment, 0, "name5=field5");
FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/true);
return false;
printf("OK\n");
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(vorbiscomment);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ vorbiscomment = FLAC__metadata_object_clone(block);
+ if(0 == vorbiscomment) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on empty array...");
vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
entry_clone_(&entry);
return false;
printf("OK\n");
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, own)...");
+ vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false);
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ if(block->data.vorbis_comment.num_comments != 6) {
+ printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, own)...");
+ vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true);
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ if(block->data.vorbis_comment.num_comments != 4) {
+ printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ printf("OK\n");
+
printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array...");
vc_delete_(vorbiscomment, 2);
if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
printf("OK\n");
-
printf("testing CUESHEET\n");
{
vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0);
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);
- memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
+ vorbiscomment->data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+ memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
vorbiscomment->data.vorbis_comment.num_comments = 2;
vorbiscomment->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)malloc_or_die_(vorbiscomment->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
vorbiscomment->data.vorbis_comment.comments[0].length = 5;
- vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5);
- memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5);
+ vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5+1);
+ memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1);
vorbiscomment->data.vorbis_comment.comments[1].length = 0;
vorbiscomment->data.vorbis_comment.comments[1].entry = 0;
}
vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0);
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);
- memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
+ vorbiscomment->data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+ memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
vorbiscomment->data.vorbis_comment.num_comments = 2;
vorbiscomment->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)malloc_or_die_(vorbiscomment->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
vorbiscomment->data.vorbis_comment.comments[0].length = 5;
- vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5);
- memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5);
+ vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5+1);
+ memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1);
vorbiscomment->data.vorbis_comment.comments[1].length = 0;
vorbiscomment->data.vorbis_comment.comments[1].entry = 0;
}
vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0);
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);
- memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length);
+ vorbiscomment->data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+ memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
vorbiscomment->data.vorbis_comment.num_comments = 2;
vorbiscomment->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)malloc_or_die_(vorbiscomment->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
vorbiscomment->data.vorbis_comment.comments[0].length = 5;
- vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5);
- memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5);
+ vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5+1);
+ memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1);
vorbiscomment->data.vorbis_comment.comments[1].length = 0;
vorbiscomment->data.vorbis_comment.comments[1].entry = 0;
}