New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix use of custom resolvers with iostream #1040
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes make sense to me. I'll leave the merge decision to @ufleisch.
I will look at it a bit more thoroughly, but adding a new abstract method to |
Indeed it would. I can think of two options:
If that's OK with you I'll try to add a new interface and see how it looks |
Possibly a third option might be:
|
d9d1318
to
27d4107
Compare
Indeed that seems much cleaner to me! Thanks for the suggestion, I updated the MR with this |
upstreamed at: taglib/taglib#1040 Fix #26602
taglib/fileref.cpp
Outdated
File *detectByResolvers(IOStream* stream, bool readAudioProperties, | ||
AudioProperties::ReadStyle audioPropertiesStyle) | ||
{ | ||
ResolverList::ConstIterator it = fileTypeResolvers.begin(); | ||
for(; it != fileTypeResolvers.end(); ++it) { | ||
const FileRef::StreamTypeResolver* streamResolver = | ||
dynamic_cast<const FileRef::StreamTypeResolver*>(*it); | ||
if (!streamResolver) | ||
continue; | ||
File *file = streamResolver->createFileFromStream(stream, readAudioProperties, audioPropertiesStyle); | ||
if(file) | ||
return file; | ||
} | ||
|
||
return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File *detectByResolvers(IOStream* stream, bool readAudioProperties, | |
AudioProperties::ReadStyle audioPropertiesStyle) | |
{ | |
ResolverList::ConstIterator it = fileTypeResolvers.begin(); | |
for(; it != fileTypeResolvers.end(); ++it) { | |
const FileRef::StreamTypeResolver* streamResolver = | |
dynamic_cast<const FileRef::StreamTypeResolver*>(*it); | |
if (!streamResolver) | |
continue; | |
File *file = streamResolver->createFileFromStream(stream, readAudioProperties, audioPropertiesStyle); | |
if(file) | |
return file; | |
} | |
return 0; | |
File *detectByResolvers(IOStream* stream, bool readAudioProperties, | |
AudioProperties::ReadStyle audioPropertiesStyle) | |
{ | |
for(ResolverList::ConstIterator it = fileTypeResolvers.begin(); | |
it != fileTypeResolvers.end(); ++it) { | |
if(const FileRef::StreamTypeResolver *streamResolver = | |
dynamic_cast<const FileRef::StreamTypeResolver*>(*it)) { | |
if(File *file = streamResolver->createFileFromStream( | |
stream, readAudioProperties, audioPropertiesStyle)) { | |
return file; | |
} | |
} | |
} | |
return 0; |
I think it is better to narrow the scope of variables and only use continue
when it would result in more readable code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with that change, but if I'm not mistaken this would require C++17 while taglib only requires C++11
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think TagLib actually requires C++11. At least in the not terribly recent past, it was all still C++98, and I'd removed the couple places that had C++11-isms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my bad, I was looking at the tests CMakeLists.txt, not the one from the library itself.
Also my bad, I just realized that the proposed sample is not in a if statement with initializer so it's fine in C++98/03, I'll push a fix
taglib/fileref.cpp
Outdated
// Try user-defined resolvers. | ||
|
||
d->file = detectByResolvers(stream->name(), readAudioProperties, audioPropertiesStyle); | ||
d->file = detectByResolvers(stream, readAudioProperties, audioPropertiesStyle); | ||
if(d->file) | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there is only a FileTypeResolver
registered (and not a StreamTypeResolver
!), detectByResolvers()
will return 0 instead of detecting by file name. So I would keep the check by file type after checking by stream.
// Try user-defined stream type resolvers.
d->file = detectByResolvers(stream, readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
// Try user-defined file type resolvers.
d->file = detectByResolvers(stream->name(), readAudioProperties, audioPropertiesStyle);
if(d->file)
return;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good point, fixed
tests/test_fileref.cpp
Outdated
{ | ||
return new Ogg::Vorbis::File(fileName); | ||
} | ||
virtual File *createFile(IOStream* s, bool, AudioProperties::ReadStyle) const | ||
{ | ||
return new Ogg::Vorbis::File(s); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | |
return new Ogg::Vorbis::File(fileName); | |
} | |
virtual File *createFile(IOStream* s, bool, AudioProperties::ReadStyle) const | |
{ | |
return new Ogg::Vorbis::File(s); | |
} | |
}; | |
{ | |
return new Ogg::Vorbis::File(fileName); | |
} | |
}; | |
class DummyStreamResolver : public FileRef::StreamTypeResolver | |
{ | |
public: | |
virtual File *createFile(FileName, bool, AudioProperties::ReadStyle) const | |
{ | |
return 0; | |
} | |
virtual File *createFileFromStream(IOStream *s, bool, AudioProperties::ReadStyle) const | |
{ | |
return new MP4::File(s); | |
} | |
}; |
This will not really work to test your resolver. First you have to implement a StreamTypeResolver
and not just add a virtual method to a FileTypeResolver
(and the method must be createFileFromStream()
). You should also keep the test with a file type resolver to make sure it still works with them. The other problem is that with the existing test, createFileFromStream()
will never be called, you have to explicitly create a FileRef
by stream, so add another test to testFileResolver
:
void testFileResolver()
{
{
FileRef f(TEST_FILE_PATH_C("xing.mp3"));
CPPUNIT_ASSERT(dynamic_cast<MPEG::File *>(f.file()) != NULL);
}
DummyResolver resolver;
FileRef::addFileTypeResolver(&resolver);
{
FileRef f(TEST_FILE_PATH_C("xing.mp3"));
CPPUNIT_ASSERT(dynamic_cast<Ogg::Vorbis::File *>(f.file()) != NULL);
}
DummyStreamResolver streamResolver;
FileRef::addFileTypeResolver(&streamResolver);
{
FileStream s(TEST_FILE_PATH_C("xing.mp3"));
FileRef f(&s);
CPPUNIT_ASSERT(dynamic_cast<MP4::File *>(f.file()) != NULL);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, thanks for providing the test code! Should be fixed in the new PR version
The main point of IOStream is to be able to use taglib with some content that can't be fopen()'ed, for instance a network file, or a local file on a system that doesn't support opening a file directly through fopen & such. This commit adds an overload for detectByResolvers that will stick to using an IOStream all the way.
when no stream resolver is available
27d4107
to
80c215e
Compare
All remarks should be addressed now, let me know if you want me to squash some changes together |
This is the version that was merged upstream so it makes sense to use it to facilitate future rebases upstream PR: taglib/taglib#1040
The current code enforces a code path that will use fopen to convert a
FileName
to an actualFile
instance, even whenFileRef::parse(IOStream*, ...)
is used, which defeats the purpose of having an IOStream overload.For reference, the associated issue on VLC's side is https://code.videolan.org/videolan/vlc/-/issues/26602