summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Coalson <jcoalson@users.sourceforce.net>2004-12-30 00:59:30 +0000
committerJosh Coalson <jcoalson@users.sourceforce.net>2004-12-30 00:59:30 +0000
commitdef597ee59e41e6ac9a170dead3e1f8300135689 (patch)
treee53902ac31b2222743b6be5b5042c6b9dcdbe9b7
parent8ddf7fb278d7a9cb2ec9a8c66a73768ef5956573 (diff)
downloadflac-def597ee59e41e6ac9a170dead3e1f8300135689.tar.gz
additions to metadata object api: more vorbiscomment functions, trailing-null on vorbis comment field values enforced everywhere
-rw-r--r--doc/html/changelog.html89
-rw-r--r--include/FLAC++/metadata.h25
-rw-r--r--include/FLAC/format.h9
-rw-r--r--include/FLAC/metadata.h191
-rw-r--r--src/flac/vorbiscomment.c2
-rw-r--r--src/libFLAC++/metadata.cpp50
-rw-r--r--src/libFLAC/metadata_iterators.c4
-rw-r--r--src/libFLAC/metadata_object.c177
-rw-r--r--src/libFLAC/stream_decoder.c6
-rw-r--r--src/metaflac/operations_shorthand_vorbiscomment.c2
-rw-r--r--src/metaflac/utils.c20
-rw-r--r--src/share/grabbag/replaygain.c2
-rw-r--r--src/test_libFLAC++/metadata_manip.cpp4
-rw-r--r--src/test_libFLAC++/metadata_object.cpp94
-rw-r--r--src/test_libFLAC++/metadata_utils.c8
-rw-r--r--src/test_libFLAC/metadata_manip.c4
-rw-r--r--src/test_libFLAC/metadata_object.c395
-rw-r--r--src/test_libFLAC/metadata_utils.c8
-rw-r--r--src/test_libOggFLAC++/metadata_utils.c8
-rw-r--r--src/test_libOggFLAC/metadata_utils.c8
20 files changed, 984 insertions, 122 deletions
diff --git a/doc/html/changelog.html b/doc/html/changelog.html
index 3b5cf76e..77168cb8 100644
--- a/doc/html/changelog.html
+++ b/doc/html/changelog.html
@@ -85,6 +85,95 @@
</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>
diff --git a/include/FLAC++/metadata.h b/include/FLAC++/metadata.h
index d7e91a6a..138580e0 100644
--- a/include/FLAC++/metadata.h
+++ b/include/FLAC++/metadata.h
@@ -492,9 +492,10 @@ namespace FLAC {
* 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
@@ -505,7 +506,10 @@ namespace FLAC {
* 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.
@@ -513,9 +517,15 @@ namespace FLAC {
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();
@@ -532,8 +542,10 @@ namespace FLAC {
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_;
@@ -548,7 +560,9 @@ namespace FLAC {
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();
};
@@ -606,6 +620,9 @@ namespace FLAC {
//! 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);
};
diff --git a/include/FLAC/format.h b/include/FLAC/format.h
index e003c34f..d4e6bcac 100644
--- a/include/FLAC/format.h
+++ b/include/FLAC/format.h
@@ -583,6 +583,15 @@ typedef struct {
/** 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;
diff --git a/include/FLAC/metadata.h b/include/FLAC/metadata.h
index bd80821a..76893aff 100644
--- a/include/FLAC/metadata.h
+++ b/include/FLAC/metadata.h
@@ -1087,6 +1087,13 @@ FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_It
* 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.
@@ -1155,8 +1162,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b
/** 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.
@@ -1168,7 +1174,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b
* \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);
@@ -1327,15 +1333,20 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_point
* \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.
@@ -1343,10 +1354,10 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMe
* \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);
@@ -1369,9 +1380,14 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__St
/** 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.
@@ -1381,18 +1397,23 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__St
* \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
@@ -1405,13 +1426,71 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__Stream
* \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.
@@ -1420,14 +1499,51 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__Str
* \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.
*
@@ -1436,14 +1552,12 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__Str
* \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
@@ -1456,13 +1570,13 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC
* \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.
@@ -1476,7 +1590,6 @@ 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);
-/*@@@@ add to unit tests */
/** Remove all Vorbis comments matching the given field name.
*
* \param object A pointer to an existing VORBIS_COMMENT object.
@@ -1561,7 +1674,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__St
* \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);
@@ -1585,7 +1698,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__Stre
* \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);
@@ -1604,7 +1717,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC
* \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);
@@ -1628,8 +1741,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMet
/** 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
@@ -1644,15 +1756,14 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMet
* \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
@@ -1668,7 +1779,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadat
* \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);
@@ -1687,7 +1798,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMeta
* \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);
@@ -1702,7 +1813,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__Stre
* \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);
diff --git a/src/flac/vorbiscomment.c b/src/flac/vorbiscomment.c
index 15e94e94..27495211 100644
--- a/src/flac/vorbiscomment.c
+++ b/src/flac/vorbiscomment.c
@@ -122,7 +122,7 @@ static FLAC__bool set_vc_field(FLAC__StreamMetadata *block, const Argument_VcFie
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";
diff --git a/src/libFLAC++/metadata.cpp b/src/libFLAC++/metadata.cpp
index 0a9cd6e1..871b01e0 100644
--- a/src/libFLAC++/metadata.cpp
+++ b/src/libFLAC++/metadata.cpp
@@ -461,12 +461,24 @@ namespace FLAC {
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());
@@ -540,18 +552,24 @@ namespace FLAC {
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());
@@ -577,18 +595,24 @@ namespace FLAC {
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;
@@ -641,17 +665,27 @@ namespace FLAC {
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 {
@@ -661,6 +695,7 @@ namespace FLAC {
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;
}
}
@@ -692,11 +727,12 @@ namespace FLAC {
}
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;
@@ -757,6 +793,12 @@ namespace FLAC {
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());
diff --git a/src/libFLAC/metadata_iterators.c b/src/libFLAC/metadata_iterators.c
index 45e5c3fe..13f1c3f7 100644
--- a/src/libFLAC/metadata_iterators.c
+++ b/src/libFLAC/metadata_iterators.c
@@ -1982,11 +1982,13 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entr
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;
diff --git a/src/libFLAC/metadata_object.c b/src/libFLAC/metadata_object.c
index 589357b6..3a613a1a 100644
--- a/src/libFLAC/metadata_object.c
+++ b/src/libFLAC/metadata_object.c
@@ -60,6 +60,18 @@ static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned
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;
@@ -70,9 +82,10 @@ static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, co
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;
@@ -194,13 +207,30 @@ static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__S
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;
}
@@ -211,6 +241,22 @@ static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__S
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;
@@ -369,7 +415,7 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type
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;
}
@@ -994,6 +1040,49 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__Str
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;
@@ -1016,32 +1105,74 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__Str
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)
@@ -1053,7 +1184,7 @@ FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__Str
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
@@ -1076,7 +1207,7 @@ FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__S
/* 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);
}
diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c
index dc687104..5995afeb 100644
--- a/src/libFLAC/stream_decoder.c
+++ b/src/libFLAC/stream_decoder.c
@@ -1167,12 +1167,13 @@ FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__Stre
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;
@@ -1193,12 +1194,13 @@ FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__Stre
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;
diff --git a/src/metaflac/operations_shorthand_vorbiscomment.c b/src/metaflac/operations_shorthand_vorbiscomment.c
index 6f146816..f92d8793 100644
--- a/src/metaflac/operations_shorthand_vorbiscomment.c
+++ b/src/metaflac/operations_shorthand_vorbiscomment.c
@@ -192,7 +192,7 @@ FLAC__bool set_vc_field(const char *filename, FLAC__StreamMetadata *block, const
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);
diff --git a/src/metaflac/utils.c b/src/metaflac/utils.c
index 9983d9b4..745e70f4 100644
--- a/src/metaflac/utils.c
+++ b/src/metaflac/utils.c
@@ -220,24 +220,16 @@ void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComme
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);
}
}
@@ -246,7 +238,7 @@ void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComme
}
}
- 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)
@@ -255,7 +247,7 @@ void write_vc_fields(const char *filename, const char *field_name, const FLAC__S
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);
}
}
diff --git a/src/share/grabbag/replaygain.c b/src/share/grabbag/replaygain.c
index 98b10886..5417fac6 100644
--- a/src/share/grabbag/replaygain.c
+++ b/src/share/grabbag/replaygain.c
@@ -102,7 +102,7 @@ static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, c
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)
diff --git a/src/test_libFLAC++/metadata_manip.cpp b/src/test_libFLAC++/metadata_manip.cpp
index 1ede4206..aee13f79 100644
--- a/src/test_libFLAC++/metadata_manip.cpp
+++ b/src/test_libFLAC++/metadata_manip.cpp
@@ -500,8 +500,8 @@ static bool generate_file_()
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;
}
diff --git a/src/test_libFLAC++/metadata_object.cpp b/src/test_libFLAC++/metadata_object.cpp
index 26b5ced5..97efbb67 100644
--- a/src/test_libFLAC++/metadata_object.cpp
+++ b/src/test_libFLAC++/metadata_object.cpp
@@ -120,16 +120,16 @@ static void init_metadata_blocks_()
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;
@@ -795,12 +795,32 @@ bool test_metadata_object_vorbiscomment()
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);
@@ -867,7 +887,7 @@ bool test_metadata_object_vorbiscomment()
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")))
@@ -876,7 +896,16 @@ bool test_metadata_object_vorbiscomment()
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")))
@@ -887,6 +916,17 @@ bool test_metadata_object_vorbiscomment()
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");
@@ -989,6 +1029,44 @@ bool test_metadata_object_vorbiscomment()
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))
diff --git a/src/test_libFLAC++/metadata_utils.c b/src/test_libFLAC++/metadata_utils.c
index 747ab061..7dc57acd 100644
--- a/src/test_libFLAC++/metadata_utils.c
+++ b/src/test_libFLAC++/metadata_utils.c
@@ -429,13 +429,13 @@ void mutils__init_metadata_blocks(
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;
}
diff --git a/src/test_libFLAC/metadata_manip.c b/src/test_libFLAC/metadata_manip.c
index b0c2a273..5cd4c080 100644
--- a/src/test_libFLAC/metadata_manip.c
+++ b/src/test_libFLAC/metadata_manip.c
@@ -507,8 +507,8 @@ static FLAC__bool generate_file_()
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;
}
diff --git a/src/test_libFLAC/metadata_object.c b/src/test_libFLAC/metadata_object.c
index cd8a527a..aee8de1f 100644
--- a/src/test_libFLAC/metadata_object.c
+++ b/src/test_libFLAC/metadata_object.c
@@ -142,16 +142,18 @@ static FLAC__bool check_seektable_(const FLAC__StreamMetadata *block, unsigned n
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;
}
@@ -200,6 +202,18 @@ static void vc_resize_(FLAC__StreamMetadata *block, unsigned num)
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)
@@ -238,6 +252,30 @@ static void vc_delete_(FLAC__StreamMetadata *block, unsigned pos)
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;
@@ -430,6 +468,7 @@ FLAC__bool test_metadata_object()
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");
@@ -843,6 +882,55 @@ FLAC__bool test_metadata_object()
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) {
@@ -896,6 +984,36 @@ FLAC__bool test_metadata_object()
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)) {
@@ -936,6 +1054,96 @@ FLAC__bool test_metadata_object()
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) {
@@ -980,6 +1188,91 @@ FLAC__bool test_metadata_object()
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);
@@ -1018,6 +1311,51 @@ FLAC__bool test_metadata_object()
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);
@@ -1062,6 +1400,58 @@ FLAC__bool test_metadata_object()
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)) {
@@ -1114,7 +1504,6 @@ FLAC__bool test_metadata_object()
printf("OK\n");
-
printf("testing CUESHEET\n");
{
diff --git a/src/test_libFLAC/metadata_utils.c b/src/test_libFLAC/metadata_utils.c
index 747ab061..7dc57acd 100644
--- a/src/test_libFLAC/metadata_utils.c
+++ b/src/test_libFLAC/metadata_utils.c
@@ -429,13 +429,13 @@ void mutils__init_metadata_blocks(
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;
}
diff --git a/src/test_libOggFLAC++/metadata_utils.c b/src/test_libOggFLAC++/metadata_utils.c
index 747ab061..7dc57acd 100644
--- a/src/test_libOggFLAC++/metadata_utils.c
+++ b/src/test_libOggFLAC++/metadata_utils.c
@@ -429,13 +429,13 @@ void mutils__init_metadata_blocks(
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;
}
diff --git a/src/test_libOggFLAC/metadata_utils.c b/src/test_libOggFLAC/metadata_utils.c
index 747ab061..7dc57acd 100644
--- a/src/test_libOggFLAC/metadata_utils.c
+++ b/src/test_libOggFLAC/metadata_utils.c
@@ -429,13 +429,13 @@ void mutils__init_metadata_blocks(
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;
}