add more convenience for manipulating vorbis comments
authorJosh Coalson <jcoalson@users.sourceforce.net>
Sat, 26 Oct 2002 04:34:16 +0000 (04:34 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Sat, 26 Oct 2002 04:34:16 +0000 (04:34 +0000)
include/FLAC/metadata.h
src/libFLAC/metadata_object.c

index 6e27ccd..ac41b89 100644 (file)
@@ -903,7 +903,9 @@ FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_It
 
 /** Create a new metadata object instance of the given type.
  *
- *  The object will be "empty"; i.e. values and data pointers will be \c 0.
+ *  The object will be "empty"; i.e. values and data pointers will be \c 0,
+ *  with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have
+ *  the vendor string set (but zero comments).
  *
  * \param type  Type of object to create
  * \retval FLAC__StreamMetadata*
@@ -1229,6 +1231,69 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__Str
  */
 FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
 
+/*@@@@ needs unit test still */
+/** Check if the given Vorbis comment entry's field name matches the given
+ *  field name.
+ *
+ * \param entry              A pointer to an existing Vorbis comment entry.
+ * \param field_name         The field name to check.
+ * \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)
+ * \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);
+
+/*@@@@ needs unit test still */
+/** Find a Vorbis comment with the given field name.
+ *
+ *  The search begins at entry number \a offset; use and offset of 0 to
+ *  search from the beginning of the comment array.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param offset      The offset into the comment array from where to start
+ *                    the search.
+ * \param field_name  The field name of the comment to find.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \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(FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
+
+/*@@@@ needs unit test still */
+/** Remove first Vorbis comment matching the given field name.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name  The field name of comment to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    \c -1 for memory allocation error, \c 0 for no matching entries,
+ *    \c 1 for one matching entry deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/*@@@@ needs unit test still */
+/** Remove all Vorbis comments matching the given field name.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name  The field name of comments to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    \c -1 for memory allocation error, \c 0 for no matching entries,
+ *    else the number of matching entries deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name);
+
 /* \} */
 
 #ifdef __cplusplus
index b2281a6..f086f38 100644 (file)
@@ -213,7 +213,18 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type
                        case FLAC__METADATA_TYPE_SEEKTABLE:
                                break;
                        case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-                               object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN + FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
+                               {
+                                       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)) {
+                                               free(object);
+                                               return 0;
+                                       }
+                                       object->length =
+                                               (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8) +
+                                               object->data.vorbis_comment.vendor_string.length +
+                                               (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8)
+                                       ;
+                               }
                                break;
                        default:
                                /* double protection: */
@@ -257,6 +268,8 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMet
                                }
                                break;
                        case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+                               if(0 != to->data.vorbis_comment.vendor_string.entry)
+                                       free(to->data.vorbis_comment.vendor_string.entry);
                                if(!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
                                        FLAC__metadata_object_delete(to);
                                        return 0;
@@ -751,3 +764,72 @@ 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)
+{
+       const FLAC__byte *eq = 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, entry->entry, field_name_length));
+#undef FLAC__STRNCASECMP
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
+{
+       const unsigned field_name_length = strlen(field_name);
+       unsigned i;
+
+       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;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+       const unsigned field_name_length = strlen(field_name);
+       unsigned i;
+
+       FLAC__ASSERT(0 != object);
+       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_delete_comment(object, i))
+                               return -1;
+                       else
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+       FLAC__bool ok = true;
+       unsigned matching = 0;
+       const unsigned field_name_length = strlen(field_name);
+       int i;
+
+       FLAC__ASSERT(0 != object);
+       FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+       /* 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)) {
+                       matching++;
+                       ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i);
+               }
+       }
+
+       return ok? (int)matching : -1;
+}