diff --git a/converters/gbsdconv/Makefile b/converters/gbsdconv/Makefile index b595457d0d52..00945c6296e2 100644 --- a/converters/gbsdconv/Makefile +++ b/converters/gbsdconv/Makefile @@ -1,6 +1,6 @@ PORTNAME= gbsdconv PORTVERSION= 11.3 -PORTREVISION= 3 +PORTREVISION= 4 CATEGORIES= converters python MAINTAINER= buganini@gmail.com diff --git a/converters/gbsdconv/files/patch-gbsdconv b/converters/gbsdconv/files/patch-gbsdconv new file mode 100644 index 000000000000..2a6056a3cede --- /dev/null +++ b/converters/gbsdconv/files/patch-gbsdconv @@ -0,0 +1,30 @@ +--- gbsdconv.orig 2024-06-06 19:33:30 UTC ++++ gbsdconv +@@ -38,10 +38,10 @@ taglib.taglib_mpeg_file.restype=c_void_p + taglib.taglib_mpeg_file.argtypes=[c_void_p] + taglib.taglib_mpeg_file.restype=c_void_p + +-taglib.taglib_mpeg_file_save3.argtypes=[c_void_p, c_int, c_bool, c_int] ++taglib.taglib_mpeg_file_save3.argtypes=[c_void_p, c_int, c_bool, c_int, c_bool] + taglib.taglib_mpeg_file_save3.restype=c_bool + +-taglib.taglib_mpeg_file_strip.argtypes=[c_void_p, c_int] ++taglib.taglib_mpeg_file_strip.argtypes=[c_void_p, c_int, c_bool] + taglib.taglib_mpeg_file_strip.restype=c_bool + + taglib.taglib_file_tag.argtypes=[c_void_p] +@@ -1281,12 +1281,12 @@ class gBsdConv(object): + + mpeg=taglib.taglib_mpeg_file(mfile) + if mpeg and builder.get_object('chk_use_id3v2_3').get_active(): +- taglib.taglib_mpeg_file_save3(mpeg, 0xffff, False, 3) ++ taglib.taglib_mpeg_file_save3(mpeg, 0xffff, False, 3, True) + else: + taglib.taglib_file_save(mfile) + + if mpeg and builder.get_object('chk_remove_id3v1').get_active(): +- taglib.taglib_mpeg_file_strip(mpeg, 0x0001) ++ taglib.taglib_mpeg_file_strip(mpeg, 0x0001, True) + + taglib.taglib_tag_free_strings() + taglib.taglib_file_free(mfile) diff --git a/converters/gbsdconv/files/patch-taglib_tag__c.cpp b/converters/gbsdconv/files/patch-taglib_tag__c.cpp new file mode 100644 index 000000000000..c3459a63aa34 --- /dev/null +++ b/converters/gbsdconv/files/patch-taglib_tag__c.cpp @@ -0,0 +1,873 @@ +--- taglib/tag_c.cpp.orig 2014-02-15 21:45:54 UTC ++++ taglib/tag_c.cpp +@@ -19,43 +19,82 @@ + * USA * + ***************************************************************************/ + ++#include "tag_c.h" ++ ++#include ++#include ++#include ++#include ++ + #ifdef HAVE_CONFIG_H +-#include "config.h" ++# include "config.h" + #endif ++#include "tstringlist.h" ++#include "tbytevectorstream.h" ++#include "tiostream.h" ++#include "tfile.h" ++#include "tpropertymap.h" ++#include "fileref.h" ++#include "asffile.h" ++#include "vorbisfile.h" ++#include "mpegfile.h" ++#include "flacfile.h" ++#include "oggflacfile.h" ++#include "mpcfile.h" ++#include "wavpackfile.h" ++#include "speexfile.h" ++#include "trueaudiofile.h" ++#include "mp4file.h" ++#include "aifffile.h" ++#include "wavfile.h" ++#include "apefile.h" ++#include "itfile.h" ++#include "modfile.h" ++#include "s3mfile.h" ++#include "xmfile.h" ++#include "opusfile.h" ++#include "dsffile.h" ++#include "dsdifffile.h" ++#include "tag.h" ++#include "id3v2framefactory.h" + +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++using namespace TagLib; + +-#include "tag_c.h" ++namespace ++{ ++ List strings; ++ bool unicodeStrings = true; ++ bool stringManagementEnabled = true; + +-using namespace TagLib; ++ char *stringToCharArray(const String &s) ++ { ++ const std::string str = s.to8Bit(unicodeStrings); + +-static List strings; +-static bool unicodeStrings = true; +-static bool stringManagementEnabled = true; ++#ifdef HAVE_ISO_STRDUP + ++ return ::_strdup(str.c_str()); ++ ++#else ++ ++ return ::strdup(str.c_str()); ++ ++#endif ++ } ++ ++ String charArrayToString(const char *s) ++ { ++ return String(s, unicodeStrings ? String::UTF8 : String::Latin1); ++ } ++} // namespace ++ + void taglib_set_strings_unicode(BOOL unicode) + { +- unicodeStrings = bool(unicode); ++ unicodeStrings = (unicode != 0); + } + + void taglib_set_string_management_enabled(BOOL management) + { +- stringManagementEnabled = bool(management); ++ stringManagementEnabled = (management != 0); + } + + void taglib_free(void* pointer) +@@ -64,69 +103,130 @@ void taglib_free(void* pointer) + } + + //////////////////////////////////////////////////////////////////////////////// +-// TagLib::File wrapper ++// TagLib::IOStream wrapper + //////////////////////////////////////////////////////////////////////////////// + ++TagLib_IOStream *taglib_memory_iostream_new(const char *data, unsigned int size) ++{ ++ return reinterpret_cast( ++ new ByteVectorStream(ByteVector(data, size))); ++} ++ ++void taglib_iostream_free(TagLib_IOStream *stream) ++{ ++ delete reinterpret_cast(stream); ++} ++ ++//////////////////////////////////////////////////////////////////////////////// ++// TagLib::FileRef wrapper ++//////////////////////////////////////////////////////////////////////////////// ++ + TagLib_File *taglib_file_new(const char *filename) + { +- return reinterpret_cast(FileRef::create(filename)); ++ return reinterpret_cast(new FileRef(filename)); + } + + TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type) + { ++ File *file = NULL; + switch(type) { + case TagLib_File_MPEG: +- return reinterpret_cast(new MPEG::File(filename)); ++ file = new MPEG::File(filename); ++ break; + case TagLib_File_OggVorbis: +- return reinterpret_cast(new Ogg::Vorbis::File(filename)); ++ file = new Ogg::Vorbis::File(filename); ++ break; + case TagLib_File_FLAC: +- return reinterpret_cast(new FLAC::File(filename)); ++ file = new FLAC::File(filename); ++ break; + case TagLib_File_MPC: +- return reinterpret_cast(new MPC::File(filename)); ++ file = new MPC::File(filename); ++ break; + case TagLib_File_OggFlac: +- return reinterpret_cast(new Ogg::FLAC::File(filename)); ++ file = new Ogg::FLAC::File(filename); ++ break; + case TagLib_File_WavPack: +- return reinterpret_cast(new WavPack::File(filename)); ++ file = new WavPack::File(filename); ++ break; + case TagLib_File_Speex: +- return reinterpret_cast(new Ogg::Speex::File(filename)); ++ file = new Ogg::Speex::File(filename); ++ break; + case TagLib_File_TrueAudio: +- return reinterpret_cast(new TrueAudio::File(filename)); ++ file = new TrueAudio::File(filename); ++ break; + case TagLib_File_MP4: +- return reinterpret_cast(new MP4::File(filename)); ++ file = new MP4::File(filename); ++ break; + case TagLib_File_ASF: +- return reinterpret_cast(new ASF::File(filename)); ++ file = new ASF::File(filename); ++ break; ++ case TagLib_File_AIFF: ++ file = new RIFF::AIFF::File(filename); ++ break; ++ case TagLib_File_WAV: ++ file = new RIFF::WAV::File(filename); ++ break; ++ case TagLib_File_APE: ++ file = new APE::File(filename); ++ break; ++ case TagLib_File_IT: ++ file = new IT::File(filename); ++ break; ++ case TagLib_File_Mod: ++ file = new Mod::File(filename); ++ break; ++ case TagLib_File_S3M: ++ file = new S3M::File(filename); ++ break; ++ case TagLib_File_XM: ++ file = new XM::File(filename); ++ break; ++ case TagLib_File_Opus: ++ file = new Ogg::Opus::File(filename); ++ break; ++ case TagLib_File_DSF: ++ file = new DSF::File(filename); ++ break; ++ case TagLib_File_DSDIFF: ++ file = new DSDIFF::File(filename); ++ break; + default: +- return 0; ++ break; + } ++ return file ? reinterpret_cast(new FileRef(file)) : NULL; ++} + +- return 0; ++TagLib_File *taglib_file_new_iostream(TagLib_IOStream *stream) ++{ ++ return reinterpret_cast( ++ new FileRef(reinterpret_cast(stream))); + } + + void taglib_file_free(TagLib_File *file) + { +- delete reinterpret_cast(file); ++ delete reinterpret_cast(file); + } + + BOOL taglib_file_is_valid(const TagLib_File *file) + { +- return reinterpret_cast(file)->isValid(); ++ return !reinterpret_cast(file)->isNull(); + } + + TagLib_Tag *taglib_file_tag(const TagLib_File *file) + { +- const File *f = reinterpret_cast(file); ++ auto f = reinterpret_cast(file); + return reinterpret_cast(f->tag()); + } + + const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file) + { +- const File *f = reinterpret_cast(file); ++ auto f = reinterpret_cast(file); + return reinterpret_cast(f->audioProperties()); + } + + BOOL taglib_file_save(TagLib_File *file) + { +- return reinterpret_cast(file)->save(); ++ return reinterpret_cast(file)->save(); + } + + //////////////////////////////////////////////////////////////////////////////// +@@ -135,8 +235,8 @@ char *taglib_tag_title(const TagLib_Tag *tag) + + char *taglib_tag_title(const TagLib_Tag *tag) + { +- const Tag *t = reinterpret_cast(tag); +- char *s = ::strdup(t->title().toCString(unicodeStrings)); ++ auto t = reinterpret_cast(tag); ++ char *s = stringToCharArray(t->title()); + if(stringManagementEnabled) + strings.append(s); + return s; +@@ -144,8 +244,8 @@ char *taglib_tag_artist(const TagLib_Tag *tag) + + char *taglib_tag_artist(const TagLib_Tag *tag) + { +- const Tag *t = reinterpret_cast(tag); +- char *s = ::strdup(t->artist().toCString(unicodeStrings)); ++ auto t = reinterpret_cast(tag); ++ char *s = stringToCharArray(t->artist()); + if(stringManagementEnabled) + strings.append(s); + return s; +@@ -153,8 +253,8 @@ char *taglib_tag_album(const TagLib_Tag *tag) + + char *taglib_tag_album(const TagLib_Tag *tag) + { +- const Tag *t = reinterpret_cast(tag); +- char *s = ::strdup(t->album().toCString(unicodeStrings)); ++ auto t = reinterpret_cast(tag); ++ char *s = stringToCharArray(t->album()); + if(stringManagementEnabled) + strings.append(s); + return s; +@@ -162,8 +262,8 @@ char *taglib_tag_comment(const TagLib_Tag *tag) + + char *taglib_tag_comment(const TagLib_Tag *tag) + { +- const Tag *t = reinterpret_cast(tag); +- char *s = ::strdup(t->comment().toCString(unicodeStrings)); ++ auto t = reinterpret_cast(tag); ++ char *s = stringToCharArray(t->comment()); + if(stringManagementEnabled) + strings.append(s); + return s; +@@ -171,8 +271,8 @@ char *taglib_tag_genre(const TagLib_Tag *tag) + + char *taglib_tag_genre(const TagLib_Tag *tag) + { +- const Tag *t = reinterpret_cast(tag); +- char *s = ::strdup(t->genre().toCString(unicodeStrings)); ++ auto t = reinterpret_cast(tag); ++ char *s = stringToCharArray(t->genre()); + if(stringManagementEnabled) + strings.append(s); + return s; +@@ -180,55 +280,55 @@ unsigned int taglib_tag_year(const TagLib_Tag *tag) + + unsigned int taglib_tag_year(const TagLib_Tag *tag) + { +- const Tag *t = reinterpret_cast(tag); ++ auto t = reinterpret_cast(tag); + return t->year(); + } + + unsigned int taglib_tag_track(const TagLib_Tag *tag) + { +- const Tag *t = reinterpret_cast(tag); ++ auto t = reinterpret_cast(tag); + return t->track(); + } + + void taglib_tag_set_title(TagLib_Tag *tag, const char *title) + { +- Tag *t = reinterpret_cast(tag); +- t->setTitle(String(title, unicodeStrings ? String::UTF8 : String::Latin1)); ++ auto t = reinterpret_cast(tag); ++ t->setTitle(charArrayToString(title)); + } + + void taglib_tag_set_artist(TagLib_Tag *tag, const char *artist) + { +- Tag *t = reinterpret_cast(tag); +- t->setArtist(String(artist, unicodeStrings ? String::UTF8 : String::Latin1)); ++ auto t = reinterpret_cast(tag); ++ t->setArtist(charArrayToString(artist)); + } + + void taglib_tag_set_album(TagLib_Tag *tag, const char *album) + { +- Tag *t = reinterpret_cast(tag); +- t->setAlbum(String(album, unicodeStrings ? String::UTF8 : String::Latin1)); ++ auto t = reinterpret_cast(tag); ++ t->setAlbum(charArrayToString(album)); + } + + void taglib_tag_set_comment(TagLib_Tag *tag, const char *comment) + { +- Tag *t = reinterpret_cast(tag); +- t->setComment(String(comment, unicodeStrings ? String::UTF8 : String::Latin1)); ++ auto t = reinterpret_cast(tag); ++ t->setComment(charArrayToString(comment)); + } + + void taglib_tag_set_genre(TagLib_Tag *tag, const char *genre) + { +- Tag *t = reinterpret_cast(tag); +- t->setGenre(String(genre, unicodeStrings ? String::UTF8 : String::Latin1)); ++ auto t = reinterpret_cast(tag); ++ t->setGenre(charArrayToString(genre)); + } + + void taglib_tag_set_year(TagLib_Tag *tag, unsigned int year) + { +- Tag *t = reinterpret_cast(tag); ++ auto t = reinterpret_cast(tag); + t->setYear(year); + } + + void taglib_tag_set_track(TagLib_Tag *tag, unsigned int track) + { +- Tag *t = reinterpret_cast(tag); ++ auto t = reinterpret_cast(tag); + t->setTrack(track); + } + +@@ -237,8 +337,8 @@ void taglib_tag_free_strings() + if(!stringManagementEnabled) + return; + +- for(List::Iterator it = strings.begin(); it != strings.end(); ++it) +- free(*it); ++ for(auto &string : std::as_const(strings)) ++ free(string); + strings.clear(); + } + +@@ -248,25 +348,25 @@ int taglib_audioproperties_length(const TagLib_AudioPr + + int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties) + { +- const AudioProperties *p = reinterpret_cast(audioProperties); +- return p->length(); ++ auto p = reinterpret_cast(audioProperties); ++ return p->lengthInSeconds(); + } + + int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties) + { +- const AudioProperties *p = reinterpret_cast(audioProperties); ++ auto p = reinterpret_cast(audioProperties); + return p->bitrate(); + } + + int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties) + { +- const AudioProperties *p = reinterpret_cast(audioProperties); ++ auto p = reinterpret_cast(audioProperties); + return p->sampleRate(); + } + + int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties) + { +- const AudioProperties *p = reinterpret_cast(audioProperties); ++ auto p = reinterpret_cast(audioProperties); + return p->channels(); + } + +@@ -293,6 +393,423 @@ void taglib_id3v2_set_default_text_encoding(TagLib_ID3 + 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; ++ ++ auto tfile = reinterpret_cast(file); ++ PropertyMap map = tfile->tag()->properties(); ++ ++ if(value) { ++ auto property = map.find(prop); ++ if(property == map.end()) { ++ map.insert(prop, StringList(charArrayToString(value))); ++ } ++ else { ++ if(append) { ++ property->second.append(charArrayToString(value)); ++ } ++ else { ++ property->second = StringList(charArrayToString(value)); ++ } ++ } ++ } ++ else { ++ map.erase(prop); ++ } ++ ++ tfile->setProperties(map); ++} ++ ++} // namespace ++ ++void taglib_property_set(TagLib_File *file, const char *prop, const char *value) ++{ ++ _taglib_property_set(file, prop, value, false); ++} ++ ++void taglib_property_set_append(TagLib_File *file, const char *prop, const char *value) ++{ ++ _taglib_property_set(file, prop, value, true); ++} ++ ++char** taglib_property_keys(const TagLib_File *file) ++{ ++ if(file == NULL) ++ return NULL; ++ ++ const PropertyMap map = reinterpret_cast(file)->properties(); ++ if(map.isEmpty()) ++ return NULL; ++ ++ auto 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(const TagLib_File *file, const char *prop) ++{ ++ if(file == NULL || prop == NULL) ++ return NULL; ++ ++ const PropertyMap map = reinterpret_cast(file)->properties(); ++ ++ auto property = map.find(prop); ++ if(property == map.end()) ++ return NULL; ++ ++ auto 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); ++} ++ ++ ++/****************************************************************************** ++ * Complex Properties API ++ ******************************************************************************/ ++ ++namespace { ++ ++bool _taglib_complex_property_set( ++ TagLib_File *file, const char *key, ++ const TagLib_Complex_Property_Attribute **value, bool append) ++{ ++ if(file == NULL || key == NULL) ++ return false; ++ ++ auto tfile = reinterpret_cast(file); ++ ++ if(value == NULL) { ++ return tfile->setComplexProperties(key, {}); ++ } ++ ++ VariantMap map; ++ const TagLib_Complex_Property_Attribute** attrPtr = value; ++ while(*attrPtr) { ++ const TagLib_Complex_Property_Attribute *attr = *attrPtr; ++ String attrKey(attr->key); ++ switch(attr->value.type) { ++ case TagLib_Variant_Void: ++ map.insert(attrKey, Variant()); ++ break; ++ case TagLib_Variant_Bool: ++ map.insert(attrKey, attr->value.value.boolValue != 0); ++ break; ++ case TagLib_Variant_Int: ++ map.insert(attrKey, attr->value.value.intValue); ++ break; ++ case TagLib_Variant_UInt: ++ map.insert(attrKey, attr->value.value.uIntValue); ++ break; ++ case TagLib_Variant_LongLong: ++ map.insert(attrKey, attr->value.value.longLongValue); ++ break; ++ case TagLib_Variant_ULongLong: ++ map.insert(attrKey, attr->value.value.uLongLongValue); ++ break; ++ case TagLib_Variant_Double: ++ map.insert(attrKey, attr->value.value.doubleValue); ++ break; ++ case TagLib_Variant_String: ++ map.insert(attrKey, charArrayToString(attr->value.value.stringValue)); ++ break; ++ case TagLib_Variant_StringList: { ++ StringList strs; ++ if(attr->value.value.stringListValue) { ++ char **s = attr->value.value.stringListValue;; ++ while(*s) { ++ strs.append(charArrayToString(*s++)); ++ } ++ } ++ map.insert(attrKey, strs); ++ break; ++ } ++ case TagLib_Variant_ByteVector: ++ map.insert(attrKey, ByteVector(attr->value.value.byteVectorValue, ++ attr->value.size)); ++ break; ++ } ++ ++attrPtr; ++ } ++ ++ return append ? tfile->setComplexProperties(key, tfile->complexProperties(key).append(map)) ++ : tfile->setComplexProperties(key, {map}); ++} ++ ++} // namespace ++ ++BOOL taglib_complex_property_set( ++ TagLib_File *file, const char *key, ++ const TagLib_Complex_Property_Attribute **value) ++{ ++ return _taglib_complex_property_set(file, key, value, false); ++} ++ ++BOOL taglib_complex_property_set_append( ++ TagLib_File *file, const char *key, ++ const TagLib_Complex_Property_Attribute **value) ++{ ++ return _taglib_complex_property_set(file, key, value, true); ++} ++ ++char** taglib_complex_property_keys(const TagLib_File *file) ++{ ++ if(file == NULL) { ++ return NULL; ++ } ++ ++ const StringList strs = reinterpret_cast(file)->complexPropertyKeys(); ++ if(strs.isEmpty()) { ++ return NULL; ++ } ++ ++ auto keys = static_cast(malloc(sizeof(char *) * (strs.size() + 1))); ++ char **keyPtr = keys; ++ ++ for(const auto &str : strs) { ++ *keyPtr++ = stringToCharArray(str); ++ } ++ *keyPtr = NULL; ++ ++ return keys; ++} ++ ++TagLib_Complex_Property_Attribute*** taglib_complex_property_get( ++ const TagLib_File *file, const char *key) ++{ ++ if(file == NULL || key == NULL) { ++ return NULL; ++ } ++ ++ const auto variantMaps = reinterpret_cast(file)->complexProperties(key); ++ if(variantMaps.isEmpty()) { ++ return NULL; ++ } ++ ++ auto props = static_cast( ++ malloc(sizeof(TagLib_Complex_Property_Attribute **) * (variantMaps.size() + 1))); ++ TagLib_Complex_Property_Attribute ***propPtr = props; ++ ++ for(const auto &variantMap : variantMaps) { ++ if(!variantMap.isEmpty()) { ++ auto attrs = static_cast( ++ malloc(sizeof(TagLib_Complex_Property_Attribute *) * (variantMap.size() + 1))); ++ auto attr = static_cast( ++ malloc(sizeof(TagLib_Complex_Property_Attribute) * variantMap.size())); ++ TagLib_Complex_Property_Attribute **attrPtr = attrs; ++ // The next assignment is redundant to silence the clang analyzer, ++ // it is done at the end of the loop, which must be entered because ++ // variantMap is not empty. ++ *attrPtr = attr; ++ for(const auto &[k, v] : variantMap) { ++ attr->key = stringToCharArray(k); ++ attr->value.size = 0; ++ switch(v.type()) { ++ case Variant::Void: ++ attr->value.type = TagLib_Variant_Void; ++ attr->value.value.stringValue = NULL; ++ break; ++ case Variant::Bool: ++ attr->value.type = TagLib_Variant_Bool; ++ attr->value.value.boolValue = v.value(); ++ break; ++ case Variant::Int: ++ attr->value.type = TagLib_Variant_Int; ++ attr->value.value.intValue = v.value(); ++ break; ++ case Variant::UInt: ++ attr->value.type = TagLib_Variant_UInt; ++ attr->value.value.uIntValue = v.value(); ++ break; ++ case Variant::LongLong: ++ attr->value.type = TagLib_Variant_LongLong; ++ attr->value.value.longLongValue = v.value(); ++ break; ++ case Variant::ULongLong: ++ attr->value.type = TagLib_Variant_ULongLong; ++ attr->value.value.uLongLongValue = v.value(); ++ break; ++ case Variant::Double: ++ attr->value.type = TagLib_Variant_Double; ++ attr->value.value.doubleValue = v.value(); ++ break; ++ case Variant::String: { ++ attr->value.type = TagLib_Variant_String; ++ auto str = v.value(); ++ attr->value.value.stringValue = stringToCharArray(str); ++ attr->value.size = str.size(); ++ break; ++ } ++ case Variant::StringList: { ++ attr->value.type = TagLib_Variant_StringList; ++ auto strs = v.value(); ++ auto strPtr = static_cast(malloc(sizeof(char *) * (strs.size() + 1))); ++ attr->value.value.stringListValue = strPtr; ++ attr->value.size = strs.size(); ++ for(const auto &str : strs) { ++ *strPtr++ = stringToCharArray(str); ++ } ++ *strPtr = NULL; ++ break; ++ } ++ case Variant::ByteVector: { ++ attr->value.type = TagLib_Variant_ByteVector; ++ const ByteVector data = v.value(); ++ auto bytePtr = static_cast(malloc(data.size())); ++ attr->value.value.byteVectorValue = bytePtr; ++ attr->value.size = data.size(); ++ ::memcpy(bytePtr, data.data(), data.size()); ++ break; ++ } ++ case Variant::ByteVectorList: ++ case Variant::VariantList: ++ case Variant::VariantMap: { ++ attr->value.type = TagLib_Variant_String; ++ std::stringstream ss; ++ ss << v; ++ attr->value.value.stringValue = stringToCharArray(ss.str()); ++ break; ++ } ++ } ++ *attrPtr++ = attr++; ++ } ++ *attrPtr = NULL; ++ *propPtr++ = attrs; ++ } ++ } ++ *propPtr = NULL; ++ return props; ++} ++ ++void taglib_picture_from_complex_property( ++ TagLib_Complex_Property_Attribute*** properties, ++ TagLib_Complex_Property_Picture_Data *picture) ++{ ++ if(!properties || !picture) { ++ return; ++ } ++ std::memset(picture, 0, sizeof(*picture)); ++ TagLib_Complex_Property_Attribute*** propPtr = properties; ++ while(!picture->data && *propPtr) { ++ TagLib_Complex_Property_Attribute** attrPtr = *propPtr; ++ while(*attrPtr) { ++ TagLib_Complex_Property_Attribute *attr = *attrPtr; ++ switch(attr->value.type) { ++ case TagLib_Variant_String: ++ if(strcmp("mimeType", attr->key) == 0) { ++ picture->mimeType = attr->value.value.stringValue; ++ } ++ else if(strcmp("description", attr->key) == 0) { ++ picture->description = attr->value.value.stringValue; ++ } ++ else if(strcmp("pictureType", attr->key) == 0) { ++ picture->pictureType = attr->value.value.stringValue; ++ } ++ break; ++ case TagLib_Variant_ByteVector: ++ if(strcmp("data", attr->key) == 0) { ++ picture->data = attr->value.value.byteVectorValue; ++ picture->size = attr->value.size; ++ } ++ break; ++ default: ++ break; ++ } ++ ++attrPtr; ++ } ++ ++propPtr; ++ } ++} ++ ++void taglib_complex_property_free_keys(char **keys) ++{ ++ if(keys == NULL) { ++ return; ++ } ++ ++ char **k = keys; ++ while(*k) { ++ free(*k++); ++ } ++ free(keys); ++} ++ ++void taglib_complex_property_free( ++ TagLib_Complex_Property_Attribute ***props) ++{ ++ if(props == NULL) { ++ return; ++ } ++ TagLib_Complex_Property_Attribute*** propPtr = props; ++ while(*propPtr) { ++ TagLib_Complex_Property_Attribute** attrPtr = *propPtr; ++ while(*attrPtr) { ++ TagLib_Complex_Property_Attribute *attr = *attrPtr; ++ switch(attr->value.type) { ++ case TagLib_Variant_String: ++ free(attr->value.value.stringValue); ++ break; ++ case TagLib_Variant_StringList: ++ if(attr->value.value.stringListValue) { ++ char **s = attr->value.value.stringListValue; ++ while(*s) { ++ free(*s++); ++ } ++ free(attr->value.value.stringListValue); ++ } ++ break; ++ case TagLib_Variant_ByteVector: ++ free(attr->value.value.byteVectorValue); ++ break; ++ case TagLib_Variant_Void: ++ case TagLib_Variant_Bool: ++ case TagLib_Variant_Int: ++ case TagLib_Variant_UInt: ++ case TagLib_Variant_LongLong: ++ case TagLib_Variant_ULongLong: ++ case TagLib_Variant_Double: ++ break; ++ } ++ free(attr->key); ++ ++attrPtr; ++ } ++ free(**propPtr); ++ free(*propPtr++); ++ } ++ free(props); ++} ++ + //////////////////////////////////////////////////////////////////////////////// + // TagLib::MPEG::File wrapper + //////////////////////////////////////////////////////////////////////////////// +@@ -302,15 +819,18 @@ TagLib_Mpeg_File *taglib_mpeg_file(TagLib_File *file) + return reinterpret_cast(dynamic_cast(reinterpret_cast(file))); + } + +-BOOL taglib_mpeg_file_save3(TagLib_Mpeg_File *file, int tags, BOOL stripOthers, int id3v2Version) ++BOOL taglib_mpeg_file_save3(TagLib_Mpeg_File *file, int tags, BOOL stripOthers, int id3v2Version, BOOL duplicateTags) + { + MPEG::File *f=reinterpret_cast(file); +- return f->save(tags, (bool)stripOthers, id3v2Version); ++ return f->save(tags, ++ stripOthers ? File::StripOthers : File::StripNone, ++ id3v2Version == 3 ? ID3v2::v3 : ID3v2::v4, ++ duplicateTags ? File::Duplicate : File::DoNotDuplicate); + } + +-BOOL taglib_mpeg_file_strip(TagLib_Mpeg_File *file, int tags) ++BOOL taglib_mpeg_file_strip(TagLib_Mpeg_File *file, int tags, BOOL freeMemory) + { + MPEG::File *f=reinterpret_cast(file); +- return f->strip(tags); ++ return f->strip(tags, freeMemory); + + } diff --git a/converters/gbsdconv/files/patch-taglib_tag__c.h b/converters/gbsdconv/files/patch-taglib_tag__c.h new file mode 100644 index 000000000000..d63029d25d7a --- /dev/null +++ b/converters/gbsdconv/files/patch-taglib_tag__c.h @@ -0,0 +1,428 @@ +--- taglib/tag_c.h.orig 2014-02-15 21:45:54 UTC ++++ taglib/tag_c.h +@@ -29,7 +29,9 @@ extern "C" { + extern "C" { + #endif + +-#if defined(_WIN32) || defined(_WIN64) ++#if defined(TAGLIB_STATIC) ++#define TAGLIB_C_EXPORT ++#elif defined(_WIN32) || defined(_WIN64) + #ifdef MAKE_TAGLIB_C_LIB + #define TAGLIB_C_EXPORT __declspec(dllexport) + #else +@@ -41,7 +43,10 @@ extern "C" { + #define TAGLIB_C_EXPORT + #endif + +-#ifndef BOOL ++#ifdef _MSC_VER ++/* minwindef.h contains typedef int BOOL */ ++#include ++#elif !defined BOOL + #define BOOL int + #endif + +@@ -55,14 +60,15 @@ extern "C" { + *******************************************************************************/ + + /* +- * These are used for type provide some type safety to the C API (as opposed to +- * using void *, but pointers to them are simply cast to the corresponding C++ ++ * These are used to give the C API some type safety (as opposed to ++ * using void * ), but pointers to them are simply cast to the corresponding C++ + * types in the implementation. + */ + + typedef struct { int dummy; } TagLib_File; + typedef struct { int dummy; } TagLib_Tag; + typedef struct { int dummy; } TagLib_AudioProperties; ++typedef struct { int dummy; } TagLib_IOStream; + typedef struct { int dummy; } TagLib_Mpeg_File; + + /*! +@@ -86,6 +92,22 @@ TAGLIB_C_EXPORT void taglib_free(void* pointer); + TAGLIB_C_EXPORT void taglib_free(void* pointer); + + /******************************************************************************* ++ * Stream API ++ ******************************************************************************/ ++ ++/*! ++ * Creates a byte vector stream from \a size bytes of \a data. ++ * Such a stream can be used with taglib_file_new_iostream() to create a file ++ * from memory. ++ */ ++TAGLIB_C_EXPORT TagLib_IOStream *taglib_memory_iostream_new(const char *data, unsigned int size); ++ ++/*! ++ * Frees and closes the stream. ++ */ ++TAGLIB_C_EXPORT void taglib_iostream_free(TagLib_IOStream *stream); ++ ++/******************************************************************************* + * File API + ******************************************************************************/ + +@@ -99,7 +121,17 @@ typedef enum { + TagLib_File_Speex, + TagLib_File_TrueAudio, + TagLib_File_MP4, +- TagLib_File_ASF ++ TagLib_File_ASF, ++ TagLib_File_AIFF, ++ TagLib_File_WAV, ++ TagLib_File_APE, ++ TagLib_File_IT, ++ TagLib_File_Mod, ++ TagLib_File_S3M, ++ TagLib_File_XM, ++ TagLib_File_Opus, ++ TagLib_File_DSF, ++ TagLib_File_DSDIFF + } TagLib_File_Type; + + /*! +@@ -118,12 +150,22 @@ TAGLIB_C_EXPORT TagLib_File *taglib_file_new_type(cons + TAGLIB_C_EXPORT TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type); + + /*! ++ * Creates a TagLib file from a \a stream. ++ * A byte vector stream can be used to read a file from memory and write to ++ * memory, e.g. when fetching network data. ++ * The stream has to be created using taglib_memory_iostream_new() and shall be ++ * freed using taglib_iostream_free() \e after this file is freed with ++ * taglib_file_free(). ++ */ ++TAGLIB_C_EXPORT TagLib_File *taglib_file_new_iostream(TagLib_IOStream *stream); ++ ++/*! + * Frees and closes the file. + */ + TAGLIB_C_EXPORT void taglib_file_free(TagLib_File *file); + + /*! +- * Returns true if the file is open and readble and valid information for ++ * Returns \c true if the file is open and readable and valid information for + * the Tag and / or AudioProperties was found. + */ + +@@ -136,7 +178,7 @@ TAGLIB_C_EXPORT TagLib_Tag *taglib_file_tag(const TagL + TAGLIB_C_EXPORT TagLib_Tag *taglib_file_tag(const TagLib_File *file); + + /*! +- * Returns a pointer to the the audio properties associated with this file. This ++ * Returns a pointer to the audio properties associated with this file. This + * will be freed automatically when the file is freed. + */ + TAGLIB_C_EXPORT const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file); +@@ -191,12 +233,12 @@ TAGLIB_C_EXPORT char *taglib_tag_genre(const TagLib_Ta + TAGLIB_C_EXPORT char *taglib_tag_genre(const TagLib_Tag *tag); + + /*! +- * Returns the tag's year or 0 if year is not set. ++ * Returns the tag's year or 0 if the year is not set. + */ + TAGLIB_C_EXPORT unsigned int taglib_tag_year(const TagLib_Tag *tag); + + /*! +- * Returns the tag's track number or 0 if track number is not set. ++ * Returns the tag's track number or 0 if the track number is not set. + */ + TAGLIB_C_EXPORT unsigned int taglib_tag_track(const TagLib_Tag *tag); + +@@ -284,14 +326,14 @@ TAGLIB_C_EXPORT TagLib_Mpeg_File *taglib_mpeg_file(Tag + TAGLIB_C_EXPORT TagLib_Mpeg_File *taglib_mpeg_file(TagLib_File *file); + + /*! +- * bool TagLib::MPEG:File::save(int tags, bool stripOthers, int id3v2Version); ++ * bool TagLib::MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, DuplicateTags duplicate); + */ +-TAGLIB_C_EXPORT BOOL taglib_mpeg_file_save3(TagLib_Mpeg_File *file, int tags, BOOL stripOthers, int id3v2Version); ++TAGLIB_C_EXPORT BOOL taglib_mpeg_file_save3(TagLib_Mpeg_File *file, int tags, BOOL stripOthers, int id3v2Version, BOOL duplicateTags); + + /*! +- * bool TagLib::MPEG:File::strip(int tags); ++ * bool TagLib::MPEG::File::strip(int tags, bool freeMemory); + */ +-TAGLIB_C_EXPORT BOOL taglib_mpeg_file_strip(TagLib_Mpeg_File *file, int tags); ++TAGLIB_C_EXPORT BOOL taglib_mpeg_file_strip(TagLib_Mpeg_File *file, int tags, BOOL freeMemory); + + /******************************************************************************* + * Special convenience ID3v2 functions +@@ -309,6 +351,275 @@ TAGLIB_C_EXPORT void taglib_id3v2_set_default_text_enc + */ + + 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(const 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(const 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); ++ ++/****************************************************************************** ++ * Complex Properties API ++ ******************************************************************************/ ++ ++/*! ++ * Types which can be stored in a TagLib_Variant. ++ * ++ * \related TagLib::Variant::Type ++ * These correspond to TagLib::Variant::Type, but ByteVectorList, VariantList, ++ * VariantMap are not supported and will be returned as their string ++ * representation. ++ */ ++typedef enum { ++ TagLib_Variant_Void, ++ TagLib_Variant_Bool, ++ TagLib_Variant_Int, ++ TagLib_Variant_UInt, ++ TagLib_Variant_LongLong, ++ TagLib_Variant_ULongLong, ++ TagLib_Variant_Double, ++ TagLib_Variant_String, ++ TagLib_Variant_StringList, ++ TagLib_Variant_ByteVector ++} TagLib_Variant_Type; ++ ++/*! ++ * Discriminated union used in complex property attributes. ++ * ++ * \e type must be set according to the \e value union used. ++ * \e size is only required for TagLib_Variant_ByteVector and must contain ++ * the number of bytes. ++ * ++ * \related TagLib::Variant. ++ */ ++typedef struct { ++ TagLib_Variant_Type type; ++ unsigned int size; ++ union { ++ char *stringValue; ++ char *byteVectorValue; ++ char **stringListValue; ++ BOOL boolValue; ++ int intValue; ++ unsigned int uIntValue; ++ long long longLongValue; ++ unsigned long long uLongLongValue; ++ double doubleValue; ++ } value; ++} TagLib_Variant; ++ ++/*! ++ * Attribute of a complex property. ++ * Complex properties consist of a NULL-terminated array of pointers to ++ * this structure with \e key and \e value. ++ */ ++typedef struct { ++ char *key; ++ TagLib_Variant value; ++} TagLib_Complex_Property_Attribute; ++ ++/*! ++ * Picture data extracted from a complex property by the convenience function ++ * taglib_picture_from_complex_property(). ++ */ ++typedef struct { ++ char *mimeType; ++ char *description; ++ char *pictureType; ++ char *data; ++ unsigned int size; ++} TagLib_Complex_Property_Picture_Data; ++ ++/*! ++ * Declare complex property attributes to set a picture. ++ * Can be used to define a variable \a var which can be used with ++ * taglib_complex_property_set() and a "PICTURE" key to set an ++ * embedded picture with the picture data \a dat of size \a siz ++ * and description \a desc, mime type \a mime and picture type ++ * \a typ (size is unsigned int, the other input parameters char *). ++ */ ++#define TAGLIB_COMPLEX_PROPERTY_PICTURE(var, dat, siz, desc, mime, typ) \ ++const TagLib_Complex_Property_Attribute \ ++var##Attrs[] = { \ ++ { \ ++ (char *)"data", \ ++ { \ ++ TagLib_Variant_ByteVector, \ ++ (siz), \ ++ { \ ++ (char *)(dat) \ ++ } \ ++ } \ ++ }, \ ++ { \ ++ (char *)"mimeType", \ ++ { \ ++ TagLib_Variant_String, \ ++ 0U, \ ++ { \ ++ (char *)(mime) \ ++ } \ ++ } \ ++ }, \ ++ { \ ++ (char *)"description", \ ++ { \ ++ TagLib_Variant_String, \ ++ 0U, \ ++ { \ ++ (char *)(desc) \ ++ } \ ++ } \ ++ }, \ ++ { \ ++ (char *)"pictureType", \ ++ { \ ++ TagLib_Variant_String, \ ++ 0U, \ ++ { \ ++ (char *)(typ) \ ++ } \ ++ } \ ++ } \ ++}; \ ++const TagLib_Complex_Property_Attribute *var[] = { \ ++ &var##Attrs[0], &var##Attrs[1], &var##Attrs[2], \ ++ &var##Attrs[3], NULL \ ++} ++ ++/*! ++ * Sets the complex property \a key with \a value. Use \a value = NULL to ++ * remove the property, otherwise it will be replaced with the NULL ++ * terminated array of attributes in \a value. ++ * ++ * A picture can be set with the TAGLIB_COMPLEX_PROPERTY_PICTURE macro: ++ * ++ * \code {.c} ++ * TagLib_File *file = taglib_file_new("myfile.mp3"); ++ * FILE *fh = fopen("mypicture.jpg", "rb"); ++ * if(fh) { ++ * fseek(fh, 0L, SEEK_END); ++ * long size = ftell(fh); ++ * fseek(fh, 0L, SEEK_SET); ++ * char *data = (char *)malloc(size); ++ * fread(data, size, 1, fh); ++ * TAGLIB_COMPLEX_PROPERTY_PICTURE(props, data, size, "Written by TagLib", ++ * "image/jpeg", "Front Cover"); ++ * taglib_complex_property_set(file, "PICTURE", props); ++ * taglib_file_save(file); ++ * free(data); ++ * fclose(fh); ++ * } ++ * \endcode ++ */ ++TAGLIB_C_EXPORT BOOL taglib_complex_property_set( ++ TagLib_File *file, const char *key, ++ const TagLib_Complex_Property_Attribute **value); ++ ++/*! ++ * Appends \a value to the complex property \a key (sets it if non-existing). ++ * Use \a value = NULL to remove all values associated with the \a key. ++ */ ++TAGLIB_C_EXPORT BOOL taglib_complex_property_set_append( ++ TagLib_File *file, const char *key, ++ const TagLib_Complex_Property_Attribute **value); ++ ++/*! ++ * Get the keys of the complex properties. ++ * ++ * \return NULL terminated array of C-strings (char *), only NULL if empty. ++ * It must be freed by the client using taglib_complex_property_free_keys(). ++ */ ++TAGLIB_C_EXPORT char** taglib_complex_property_keys(const TagLib_File *file); ++ ++/*! ++ * Get value(s) of complex property \a key. ++ * ++ * \return NULL terminated array of property values, which are themselves an ++ * array of property attributes, only NULL if empty. ++ * It must be freed by the client using taglib_complex_property_free(). ++ */ ++TAGLIB_C_EXPORT TagLib_Complex_Property_Attribute*** taglib_complex_property_get( ++ const TagLib_File *file, const char *key); ++ ++/*! ++ * Extract the complex property values of a picture. ++ * ++ * This function can be used to get the data from a "PICTURE" complex property ++ * without having to traverse the whole variant map. A picture can be ++ * retrieved like this: ++ * ++ * \code {.c} ++ * TagLib_File *file = taglib_file_new("myfile.mp3"); ++ * TagLib_Complex_Property_Attribute*** properties = ++ * taglib_complex_property_get(file, "PICTURE"); ++ * TagLib_Complex_Property_Picture_Data picture; ++ * taglib_picture_from_complex_property(properties, &picture); ++ * // Do something with picture.mimeType, picture.description, ++ * // picture.pictureType, picture.data, picture.size, e.g. extract it. ++ * FILE *fh = fopen("mypicture.jpg", "wb"); ++ * if(fh) { ++ * fwrite(picture.data, picture.size, 1, fh); ++ * fclose(fh); ++ * } ++ * taglib_complex_property_free(properties); ++ * \endcode ++ * ++ * Note that the data in \a picture contains pointers to data in \a properties, ++ * i.e. it only lives as long as the properties, until they are freed with ++ * taglib_complex_property_free(). ++ * If you want to access multiple pictures or additional properties of FLAC ++ * pictures ("width", "height", "numColors", "colorDepth" int values), you ++ * have to traverse the \a properties yourself. ++ */ ++TAGLIB_C_EXPORT void taglib_picture_from_complex_property( ++ TagLib_Complex_Property_Attribute*** properties, ++ TagLib_Complex_Property_Picture_Data *picture); ++ ++/*! ++ * Frees the NULL terminated array \a keys (as returned by ++ * taglib_complex_property_keys()) and the C-strings it contains. ++ */ ++TAGLIB_C_EXPORT void taglib_complex_property_free_keys(char **keys); ++ ++/*! ++ * Frees the NULL terminated array \a props of property attribute arrays ++ * (as returned by taglib_complex_property_get()) and the data such as ++ * C-strings and byte vectors contained in these attributes. ++ */ ++TAGLIB_C_EXPORT void taglib_complex_property_free( ++ TagLib_Complex_Property_Attribute ***props); + + #ifdef __cplusplus + }