From e20a53afbbc1d81e31a4fc8614e1b00fd4176ee4 Mon Sep 17 00:00:00 2001 From: whatdoineed2do Date: Sun, 9 Jul 2023 18:48:27 +0100 Subject: [PATCH] C bindings - properties i/f (#1091) Support properties in C bindings --------- Co-authored-by: whatdoineed2do/Ray Co-authored-by: Urs Fleisch --- bindings/c/tag_c.cpp | 102 +++++++++++++++++++++++++++++++++++++++++ bindings/c/tag_c.h | 37 +++++++++++++++ examples/tagreader_c.c | 33 ++++++++++++- 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/bindings/c/tag_c.cpp b/bindings/c/tag_c.cpp index 612ca5b0..21875520 100644 --- a/bindings/c/tag_c.cpp +++ b/bindings/c/tag_c.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include "tag_c.h" @@ -313,3 +314,104 @@ void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding) ID3v2::FrameFactory::instance()->setDefaultTextEncoding(type); } + + +/****************************************************************************** + * Properties API + ******************************************************************************/ +namespace { + +void _taglib_property_set(TagLib_File *file, const char* prop, const char* value, bool append) +{ + if(file == NULL || prop == NULL) + return; + + File *tfile = reinterpret_cast(file); + PropertyMap map = tfile->tag()->properties(); + + if(value) { + TagLib::PropertyMap::Iterator property = map.find(prop); + if(property == map.end()) { + map.insert(prop, StringList(value)); + } + else { + if(append) { + property->second.append(value); + } + else { + property->second = StringList(value); + } + } + } + else { + map.erase(prop); + } + + tfile->setProperties(map); +} + +} // namespace + +void taglib_property_set(TagLib_File *f, const char *prop, const char *value) +{ + _taglib_property_set(f, prop, value, false); +} + +void taglib_property_set_append(TagLib_File *f, const char *prop, const char *value) +{ + _taglib_property_set(f, prop, value, true); +} + +char** taglib_property_keys(TagLib_File *file) +{ + if(file == NULL) + return NULL; + + const PropertyMap map = reinterpret_cast(file)->properties(); + if(map.isEmpty()) + return NULL; + + char **props = static_cast(malloc(sizeof(char *) * (map.size() + 1))); + char **pp = props; + + for(const auto &i : map) { + *pp++ = stringToCharArray(i.first); + } + *pp = NULL; + + return props; +} + +char **taglib_property_get(TagLib_File *file, const char *prop) +{ + if(file == NULL || prop == NULL) + return NULL; + + const PropertyMap map = reinterpret_cast(file)->properties(); + + TagLib::PropertyMap::ConstIterator property = map.find(prop); + if(property == map.end()) + return NULL; + + char **props = static_cast(malloc(sizeof(char *) * (property->second.size() + 1))); + char **pp = props; + + for(const auto &i : property->second) { + *pp++ = stringToCharArray(i); + } + *pp = NULL; + + return props; +} + +void taglib_property_free(char **props) +{ + if(props == NULL) + return; + + char **p = props; + while(*p) { + free(*p++); + } + free(props); +} diff --git a/bindings/c/tag_c.h b/bindings/c/tag_c.h index 8d5f85ff..23e93854 100644 --- a/bindings/c/tag_c.h +++ b/bindings/c/tag_c.h @@ -292,6 +292,43 @@ typedef enum { TAGLIB_C_EXPORT void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding); +/****************************************************************************** + * Properties API + ******************************************************************************/ + +/*! + * Sets the property \a prop with \a value. Use \a value = NULL to remove + * the property, otherwise it will be replaced. + */ +TAGLIB_C_EXPORT void taglib_property_set(TagLib_File *file, const char *prop, const char *value); + +/*! + * Appends \a value to the property \a prop (sets it if non-existing). + * Use \a value = NULL to remove all values associated with the property. + */ +TAGLIB_C_EXPORT void taglib_property_set_append(TagLib_File *file, const char *prop, const char *value); + +/*! + * Get the keys of the property map. + * + * \return NULL terminated array of C-strings (char *), only NULL if empty. + * It must be freed by the client using taglib_property_free(). + */ +TAGLIB_C_EXPORT char** taglib_property_keys(TagLib_File *file); + +/*! + * Get value(s) of property \a prop. + * + * \return NULL terminated array of C-strings (char *), only NULL if empty. + It must be freed by the client using taglib_property_free(). + */ +TAGLIB_C_EXPORT char** taglib_property_get(TagLib_File *file, const char *prop); + +/*! + * Frees the NULL terminated array \a props and the C-strings it contains. + */ +TAGLIB_C_EXPORT void taglib_property_free(char **props); + #ifdef __cplusplus } #endif diff --git a/examples/tagreader_c.c b/examples/tagreader_c.c index 04369926..f67b53e7 100644 --- a/examples/tagreader_c.c +++ b/examples/tagreader_c.c @@ -23,6 +23,7 @@ */ #include +#include #include #ifndef FALSE @@ -37,8 +38,9 @@ int main(int argc, char *argv[]) TagLib_File *file; TagLib_Tag *tag; const TagLib_AudioProperties *properties; + char **propertiesMap; - taglib_set_strings_unicode(FALSE); + taglib_set_strings_unicode(1); for(i = 1; i < argc; i++) { printf("******************** \"%s\" ********************\n", argv[i]); @@ -50,9 +52,10 @@ int main(int argc, char *argv[]) tag = taglib_file_tag(file); properties = taglib_file_audioproperties(file); + propertiesMap = taglib_property_keys(file); if(tag != NULL) { - printf("-- TAG --\n"); + printf("-- TAG (basic) --\n"); printf("title - \"%s\"\n", taglib_tag_title(tag)); printf("artist - \"%s\"\n", taglib_tag_artist(tag)); printf("album - \"%s\"\n", taglib_tag_album(tag)); @@ -62,6 +65,31 @@ int main(int argc, char *argv[]) printf("genre - \"%s\"\n", taglib_tag_genre(tag)); } + + if(propertiesMap != NULL) { + char **keyPtr = propertiesMap; + int longest = 0; + while(*keyPtr) { + int len = (int)strlen(*keyPtr++); + if(len > longest) { + longest = len; + } + } + keyPtr = propertiesMap; + + printf("-- TAG (properties) --\n"); + while(*keyPtr) { + char **valPtr; + char **propertyValues = valPtr = taglib_property_get(file, *keyPtr); + while(valPtr && *valPtr) + { + printf("%-*s - \"%s\"\n", longest, *keyPtr, *valPtr++); + } + taglib_property_free(propertyValues); + ++keyPtr; + } + } + if(properties != NULL) { seconds = taglib_audioproperties_length(properties) % 60; minutes = (taglib_audioproperties_length(properties) - seconds) / 60; @@ -73,6 +101,7 @@ int main(int argc, char *argv[]) printf("length - %i:%02i\n", minutes, seconds); } + taglib_property_free(propertiesMap); taglib_tag_free_strings(); taglib_file_free(file); }