Remove deprecated FileRef::create() method

In order to achieve this, the TagLib_File type of the C bindings is now
a FileRef and no longer a File. The support for the .oga extension has been
ported to FileRef(), so that taglib_file_new() should still behave the
same, but additionally also support content based file type detection.
This commit is contained in:
Urs Fleisch 2023-10-21 15:24:44 +02:00
parent 8d98ebf24b
commit 0db487bf61
4 changed files with 46 additions and 140 deletions

View File

@ -92,67 +92,79 @@ void taglib_free(void* pointer)
}
////////////////////////////////////////////////////////////////////////////////
// TagLib::File wrapper
// TagLib::FileRef wrapper
////////////////////////////////////////////////////////////////////////////////
TagLib_File *taglib_file_new(const char *filename)
{
return reinterpret_cast<TagLib_File *>(FileRef::create(filename));
return reinterpret_cast<TagLib_File *>(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<TagLib_File *>(new MPEG::File(filename));
file = new MPEG::File(filename);
break;
case TagLib_File_OggVorbis:
return reinterpret_cast<TagLib_File *>(new Ogg::Vorbis::File(filename));
file = new Ogg::Vorbis::File(filename);
break;
case TagLib_File_FLAC:
return reinterpret_cast<TagLib_File *>(new FLAC::File(filename));
file = new FLAC::File(filename);
break;
case TagLib_File_MPC:
return reinterpret_cast<TagLib_File *>(new MPC::File(filename));
file = new MPC::File(filename);
break;
case TagLib_File_OggFlac:
return reinterpret_cast<TagLib_File *>(new Ogg::FLAC::File(filename));
file = new Ogg::FLAC::File(filename);
break;
case TagLib_File_WavPack:
return reinterpret_cast<TagLib_File *>(new WavPack::File(filename));
file = new WavPack::File(filename);
break;
case TagLib_File_Speex:
return reinterpret_cast<TagLib_File *>(new Ogg::Speex::File(filename));
file = new Ogg::Speex::File(filename);
break;
case TagLib_File_TrueAudio:
return reinterpret_cast<TagLib_File *>(new TrueAudio::File(filename));
file = new TrueAudio::File(filename);
break;
case TagLib_File_MP4:
return reinterpret_cast<TagLib_File *>(new MP4::File(filename));
file = new MP4::File(filename);
break;
case TagLib_File_ASF:
return reinterpret_cast<TagLib_File *>(new ASF::File(filename));
file = new ASF::File(filename);
break;
default:
return 0;
break;
}
return file ? reinterpret_cast<TagLib_File *>(new FileRef(file)) : NULL;
}
void taglib_file_free(TagLib_File *file)
{
delete reinterpret_cast<File *>(file);
delete reinterpret_cast<FileRef *>(file);
}
BOOL taglib_file_is_valid(const TagLib_File *file)
{
return reinterpret_cast<const File *>(file)->isValid();
return !reinterpret_cast<const FileRef *>(file)->isNull();
}
TagLib_Tag *taglib_file_tag(const TagLib_File *file)
{
auto f = reinterpret_cast<const File *>(file);
auto f = reinterpret_cast<const FileRef *>(file);
return reinterpret_cast<TagLib_Tag *>(f->tag());
}
const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file)
{
auto f = reinterpret_cast<const File *>(file);
auto f = reinterpret_cast<const FileRef *>(file);
return reinterpret_cast<const TagLib_AudioProperties *>(f->audioProperties());
}
BOOL taglib_file_save(TagLib_File *file)
{
return reinterpret_cast<File *>(file)->save();
return reinterpret_cast<FileRef *>(file)->save();
}
////////////////////////////////////////////////////////////////////////////////
@ -330,7 +342,7 @@ void _taglib_property_set(TagLib_File *file, const char* prop, const char* value
if(file == NULL || prop == NULL)
return;
auto tfile = reinterpret_cast<File *>(file);
auto tfile = reinterpret_cast<FileRef *>(file);
PropertyMap map = tfile->tag()->properties();
if(value) {
@ -371,7 +383,7 @@ char** taglib_property_keys(TagLib_File *file)
if(file == NULL)
return NULL;
const PropertyMap map = reinterpret_cast<const File *>(file)->properties();
const PropertyMap map = reinterpret_cast<const FileRef *>(file)->properties();
if(map.isEmpty())
return NULL;
@ -391,7 +403,7 @@ char **taglib_property_get(TagLib_File *file, const char *prop)
if(file == NULL || prop == NULL)
return NULL;
const PropertyMap map = reinterpret_cast<const File *>(file)->properties();
const PropertyMap map = reinterpret_cast<const FileRef *>(file)->properties();
auto property = map.find(prop);
if(property == map.end())
@ -434,7 +446,7 @@ bool _taglib_complex_property_set(
if(file == NULL || key == NULL)
return false;
auto tfile = reinterpret_cast<File *>(file);
auto tfile = reinterpret_cast<FileRef *>(file);
if(value == NULL) {
return tfile->setComplexProperties(key, {});
@ -516,7 +528,7 @@ char** taglib_complex_property_keys(TagLib_File *file)
return NULL;
}
const StringList strs = reinterpret_cast<const File *>(file)->complexPropertyKeys();
const StringList strs = reinterpret_cast<const FileRef *>(file)->complexPropertyKeys();
if(strs.isEmpty()) {
return NULL;
}
@ -539,7 +551,7 @@ TagLib_Complex_Property_Attribute*** taglib_complex_property_get(
return NULL;
}
const auto variantMaps = reinterpret_cast<const File *>(file)->complexProperties(key);
const auto variantMaps = reinterpret_cast<const FileRef *>(file)->complexProperties(key);
if(variantMaps.isEmpty()) {
return NULL;
}

View File

@ -138,6 +138,14 @@ namespace
file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
else if(ext == "OGG")
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "OGA") {
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
if(!file->isValid()) {
delete file;
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
}
}
else if(ext == "FLAC")
file = new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
else if(ext == "MPC")
@ -236,80 +244,6 @@ namespace
return nullptr;
}
// Internal function that supports FileRef::create().
// This looks redundant, but necessary in order not to change the previous
// behavior of FileRef::create().
File* createInternal(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
if(auto file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle))
return file;
#ifdef _WIN32
const String s = fileName.toString();
#else
const String s(fileName);
#endif
String ext;
const int pos = s.rfind(".");
if(pos != -1)
ext = s.substr(pos + 1).upper();
if(ext.isEmpty())
return nullptr;
if(ext == "MP3")
return new MPEG::File(fileName, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
if(ext == "OGG")
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OGA") {
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
auto file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
if(file->isValid())
return file;
delete file;
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
}
if(ext == "FLAC")
return new FLAC::File(fileName, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
if(ext == "MPC")
return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WV")
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "SPX")
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OPUS")
return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "TTA")
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V")
return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WMA" || ext == "ASF")
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WAV")
return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "APE")
return new APE::File(fileName, readAudioProperties, audioPropertiesStyle);
// module, nst and wow are possible but uncommon extensions
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "S3M")
return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "IT")
return new IT::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "DSF")
return new DSF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "DFF" || ext == "DSDIFF")
return new DSDIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
return nullptr;
}
} // namespace
class FileRef::FileRefPrivate
@ -529,12 +463,6 @@ bool FileRef::operator!=(const FileRef &ref) const
return (ref.d->file != d->file);
}
File *FileRef::create(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle) // static
{
return createInternal(fileName, readAudioProperties, audioPropertiesStyle);
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

View File

@ -63,7 +63,7 @@ namespace TagLib {
//! A class for pluggable file type resolution.
/*!
* This class is used to add extend TagLib's very basic file name based file
* This class is used to extend TagLib's very basic file name based file
* type resolution.
*
* This can be accomplished with:
@ -104,7 +104,7 @@ namespace TagLib {
/*!
* This method must be overridden to provide an additional file type
* resolver. If the resolver is able to determine the file type it should
* return a valid File object; if not it should return 0.
* return a valid File object; if not it should return nullptr.
*
* \note The created file is then owned by the FileRef and should not be
* deleted. Deletion will happen automatically when the FileRef passes
@ -374,22 +374,6 @@ namespace TagLib {
*/
bool operator!=(const FileRef &ref) const;
/*!
* A simple implementation of file type guessing. If \a readAudioProperties
* is true then the audio properties will be read using
* \a audioPropertiesStyle. If \a readAudioProperties is false then
* \a audioPropertiesStyle will be ignored.
*
* \note You generally shouldn't use this method, but instead the constructor
* directly.
*
* \deprecated Use FileRef(FileName, bool, AudioProperties::ReadStyle).
*/
// Kept because it is used for the C bindings
static File *create(FileName fileName,
bool readAudioProperties = true,
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
private:
void parse(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
void parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);

View File

@ -104,7 +104,6 @@ class TestFileRef : public CppUnit::TestFixture
CPPUNIT_TEST(testDSF);
CPPUNIT_TEST(testDSDIFF);
CPPUNIT_TEST(testUnsupported);
CPPUNIT_TEST(testCreate);
CPPUNIT_TEST(testAudioProperties);
CPPUNIT_TEST(testDefaultFileExtensions);
CPPUNIT_TEST(testFileResolver);
@ -354,23 +353,6 @@ public:
CPPUNIT_ASSERT(f2.isNull());
}
void testCreate()
{
// This is deprecated. But worth it to test.
File *f = FileRef::create(TEST_FILE_PATH_C("empty_vorbis.oga"));
CPPUNIT_ASSERT(dynamic_cast<Ogg::Vorbis::File*>(f));
delete f;
f = FileRef::create(TEST_FILE_PATH_C("xing.mp3"));
CPPUNIT_ASSERT(dynamic_cast<MPEG::File*>(f));
delete f;
f = FileRef::create(TEST_FILE_PATH_C("test.xm"));
CPPUNIT_ASSERT(dynamic_cast<XM::File*>(f));
delete f;
}
void testAudioProperties()
{
FileRef f(TEST_FILE_PATH_C("xing.mp3"));