From 931bb042c396f3452b0a8a82b88b93e0fe16dbc9 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Fri, 3 Feb 2017 17:52:27 +0900 Subject: [PATCH 1/8] Enable FileRef to detect file types by the actual content of a stream. FileRef doesn't work with ByteVectorStream as reported at #796, since ByteVectorStream is not associated with a file name and FileRef detects file types based on file extensions. This commit makes FileRef to work with ByteVectorStream by enabling it to detect file types based on the actual content of a stream. --- taglib/ape/apefile.cpp | 12 ++ taglib/ape/apefile.h | 9 ++ taglib/asf/asffile.cpp | 13 ++ taglib/asf/asffile.h | 9 ++ taglib/fileref.cpp | 213 +++++++++++++++++++---------- taglib/fileref.h | 4 +- taglib/flac/flacfile.cpp | 12 ++ taglib/flac/flacfile.h | 9 ++ taglib/mp4/mp4file.cpp | 18 +++ taglib/mp4/mp4file.h | 9 ++ taglib/mpc/mpcfile.cpp | 13 ++ taglib/mpc/mpcfile.h | 9 ++ taglib/mpeg/mpegfile.cpp | 57 ++++++++ taglib/mpeg/mpegfile.h | 9 ++ taglib/mpeg/mpegheader.cpp | 21 +-- taglib/mpeg/mpegutils.h | 6 +- taglib/ogg/flac/oggflacfile.cpp | 13 ++ taglib/ogg/flac/oggflacfile.h | 8 ++ taglib/ogg/opus/opusfile.cpp | 13 ++ taglib/ogg/opus/opusfile.h | 9 ++ taglib/ogg/speex/speexfile.cpp | 13 ++ taglib/ogg/speex/speexfile.h | 9 ++ taglib/ogg/vorbis/vorbisfile.cpp | 14 +- taglib/ogg/vorbis/vorbisfile.h | 8 ++ taglib/riff/aiff/aifffile.cpp | 13 ++ taglib/riff/aiff/aifffile.h | 8 ++ taglib/riff/wav/wavfile.cpp | 21 ++- taglib/riff/wav/wavfile.h | 9 ++ taglib/tagutils.cpp | 22 +++ taglib/tagutils.h | 5 + taglib/trueaudio/trueaudiofile.cpp | 12 ++ taglib/trueaudio/trueaudiofile.h | 9 ++ taglib/wavpack/wavpackfile.cpp | 12 ++ taglib/wavpack/wavpackfile.h | 8 ++ tests/test_fileref.cpp | 104 +++++++++++--- 35 files changed, 613 insertions(+), 120 deletions(-) diff --git a/taglib/ape/apefile.cpp b/taglib/ape/apefile.cpp index 9f298aaf..fb01e4a2 100644 --- a/taglib/ape/apefile.cpp +++ b/taglib/ape/apefile.cpp @@ -83,6 +83,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool APE::File::isValidStream(IOStream *stream) +{ + // An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede. + + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); + return (buffer.find("MAC ") >= 0); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/ape/apefile.h b/taglib/ape/apefile.h index cfb19ff7..a7c870b4 100644 --- a/taglib/ape/apefile.h +++ b/taglib/ape/apefile.h @@ -211,6 +211,15 @@ namespace TagLib { */ bool hasID3v1Tag() const; + /*! + * Returns whether or not the given \a stream can be opened as an APE + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/asf/asffile.cpp b/taglib/asf/asffile.cpp index 8f395265..c209a640 100644 --- a/taglib/asf/asffile.cpp +++ b/taglib/asf/asffile.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "asffile.h" #include "asftag.h" @@ -473,6 +474,18 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in } } +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool ASF::File::isValidStream(IOStream *stream) +{ + // An ASF file has to start with the designated GUID. + + const ByteVector id = Utils::readHeader(stream, 16, false); + return (id == headerGuid); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/asf/asffile.h b/taglib/asf/asffile.h index b674da79..7df5a797 100644 --- a/taglib/asf/asffile.h +++ b/taglib/asf/asffile.h @@ -115,6 +115,15 @@ namespace TagLib { */ virtual bool save(); + /*! + * Returns whether or not the given \a stream can be opened as an ASF + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: void read(); diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index dca69f6a..cad1ae50 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -28,6 +28,7 @@ ***************************************************************************/ #include +#include #include #include #include @@ -59,41 +60,14 @@ namespace typedef List ResolverList; ResolverList fileTypeResolvers; - // Templatized internal functions. T should be String or IOStream*. + // Detect the file type by user-defined resolvers. - template - FileName toFileName(T arg); - - template <> - FileName toFileName(IOStream *arg) - { - return arg->name(); - } - - template <> - FileName toFileName(FileName arg) - { - return arg; - } - - template - File *resolveFileType(T arg, bool readProperties, - AudioProperties::ReadStyle style); - - template <> - File *resolveFileType(IOStream *arg, bool readProperties, - AudioProperties::ReadStyle style) - { - return 0; - } - - template <> - File *resolveFileType(FileName arg, bool readProperties, - AudioProperties::ReadStyle style) + File *detectByResolvers(FileName fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) { ResolverList::ConstIterator it = fileTypeResolvers.begin(); for(; it != fileTypeResolvers.end(); ++it) { - File *file = (*it)->createFile(arg, readProperties, style); + File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle); if(file) return file; } @@ -101,18 +75,15 @@ namespace return 0; } - template - File* createInternal(T arg, bool readAudioProperties, - AudioProperties::ReadStyle audioPropertiesStyle) - { - File *file = resolveFileType(arg, readAudioProperties, audioPropertiesStyle); - if(file) - return file; + // Detect the file type based on the file extension. + File* detectByExtension(IOStream *stream, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) + { #ifdef _WIN32 - const String s = toFileName(arg).toString(); + const String s = stream->name().toString(); #else - const String s(toFileName(arg)); + const String s(stream->name()); #endif String ext; @@ -127,49 +98,91 @@ namespace if(ext.isEmpty()) return 0; + // .oga can be any audio in the Ogg container. So leave it to content-based detection. + if(ext == "MP3") - return new MPEG::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + return new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); if(ext == "OGG") - return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle); - if(ext == "OGA") { - /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ - File *file = new Ogg::FLAC::File(arg, readAudioProperties, audioPropertiesStyle); - if(file->isValid()) - return file; - delete file; - return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle); - } + return new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "FLAC") - return new FLAC::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + return new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); if(ext == "MPC") - return new MPC::File(arg, readAudioProperties, audioPropertiesStyle); + return new MPC::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "WV") - return new WavPack::File(arg, readAudioProperties, audioPropertiesStyle); + return new WavPack::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "SPX") - return new Ogg::Speex::File(arg, readAudioProperties, audioPropertiesStyle); + return new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "OPUS") - return new Ogg::Opus::File(arg, readAudioProperties, audioPropertiesStyle); + return new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "TTA") - return new TrueAudio::File(arg, readAudioProperties, audioPropertiesStyle); + return new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V") - return new MP4::File(arg, readAudioProperties, audioPropertiesStyle); + return new MP4::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "WMA" || ext == "ASF") - return new ASF::File(arg, readAudioProperties, audioPropertiesStyle); + return new ASF::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC") - return new RIFF::AIFF::File(arg, readAudioProperties, audioPropertiesStyle); + return new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "WAV") - return new RIFF::WAV::File(arg, readAudioProperties, audioPropertiesStyle); + return new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "APE") - return new APE::File(arg, readAudioProperties, audioPropertiesStyle); + return new APE::File(stream, readAudioProperties, audioPropertiesStyle); // module, nst and wow are possible but uncommon extensions if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") - return new Mod::File(arg, readAudioProperties, audioPropertiesStyle); + return new Mod::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "S3M") - return new S3M::File(arg, readAudioProperties, audioPropertiesStyle); + return new S3M::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "IT") - return new IT::File(arg, readAudioProperties, audioPropertiesStyle); + return new IT::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "XM") - return new XM::File(arg, readAudioProperties, audioPropertiesStyle); + return new XM::File(stream, readAudioProperties, audioPropertiesStyle); + + return 0; + } + + // Detect the file type based on the actual content of the stream. + + File *detectByContent(IOStream *stream, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) + { + File *file = 0; + + if(MPEG::File::isValidStream(stream)) + file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + else if(Ogg::Vorbis::File::isValidStream(stream)) + file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle); + else if(Ogg::FLAC::File::isValidStream(stream)) + file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle); + else if(FLAC::File::isValidStream(stream)) + file = new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); + else if(MPC::File::isValidStream(stream)) + file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle); + else if(WavPack::File::isValidStream(stream)) + file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle); + else if(Ogg::Speex::File::isValidStream(stream)) + file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle); + else if(Ogg::Opus::File::isValidStream(stream)) + file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle); + else if(TrueAudio::File::isValidStream(stream)) + file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle); + else if(MP4::File::isValidStream(stream)) + file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle); + else if(ASF::File::isValidStream(stream)) + file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle); + else if(RIFF::AIFF::File::isValidStream(stream)) + file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle); + else if(RIFF::WAV::File::isValidStream(stream)) + file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle); + else if(APE::File::isValidStream(stream)) + file = new APE::File(stream, readAudioProperties, audioPropertiesStyle); + + // isValidStream() only does a quick check, so double check the file here. + + if(file) { + if(file->isValid()) + return file; + else + delete file; + } return 0; } @@ -178,15 +191,18 @@ namespace class FileRef::FileRefPrivate : public RefCounter { public: - FileRefPrivate(File *f) : + FileRefPrivate() : RefCounter(), - file(f) {} + file(0), + stream(0) {} ~FileRefPrivate() { delete file; + delete stream; } - File *file; + File *file; + IOStream *stream; }; //////////////////////////////////////////////////////////////////////////////// @@ -194,24 +210,27 @@ public: //////////////////////////////////////////////////////////////////////////////// FileRef::FileRef() : - d(new FileRefPrivate(0)) + d(new FileRefPrivate()) { } FileRef::FileRef(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) : - d(new FileRefPrivate(createInternal(fileName, readAudioProperties, audioPropertiesStyle))) + d(new FileRefPrivate()) { + parse(fileName, readAudioProperties, audioPropertiesStyle); } FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) : - d(new FileRefPrivate(createInternal(stream, readAudioProperties, audioPropertiesStyle))) + d(new FileRefPrivate()) { + parse(stream, readAudioProperties, audioPropertiesStyle); } FileRef::FileRef(File *file) : - d(new FileRefPrivate(file)) + d(new FileRefPrivate()) { + d->file = file; } FileRef::FileRef(const FileRef &ref) : @@ -331,5 +350,53 @@ bool FileRef::operator!=(const FileRef &ref) const File *FileRef::create(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) // static { - return createInternal(fileName, readAudioProperties, audioPropertiesStyle); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void FileRef::parse(FileName fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) +{ + // Try user-defined resolvers. + + d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle); + if(d->file) + return; + + // Try to resolve file types based on the file extension. + + d->stream = new FileStream(fileName); + d->file = detectByExtension(d->stream, readAudioProperties, audioPropertiesStyle); + if(d->file) + return; + + // At last, try to resolve file types based on the actual content. + + d->file = detectByContent(d->stream, readAudioProperties, audioPropertiesStyle); + if(d->file) + return; + + // Stream have to be closed here if failed to resolve file types. + + delete d->stream; + d->stream = 0; +} + +void FileRef::parse(IOStream *stream, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) +{ + // User-defined resolvers won't work with a stream. + + // Try to resolve file types based on the file extension. + + d->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle); + if(d->file) + return; + + // At last, try to resolve file types based on the actual content of the file. + + d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle); } diff --git a/taglib/fileref.h b/taglib/fileref.h index a12b1a9b..c36f54cb 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -274,8 +274,10 @@ namespace TagLib { 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); + class FileRefPrivate; FileRefPrivate *d; }; diff --git a/taglib/flac/flacfile.cpp b/taglib/flac/flacfile.cpp index b6b72960..780ab1c3 100644 --- a/taglib/flac/flacfile.cpp +++ b/taglib/flac/flacfile.cpp @@ -95,6 +95,18 @@ public: bool scanned; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool FLAC::File::isValidStream(IOStream *stream) +{ + // A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede. + + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); + return (buffer.find("fLaC") >= 0); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/flac/flacfile.h b/taglib/flac/flacfile.h index 65d85679..56755ec5 100644 --- a/taglib/flac/flacfile.h +++ b/taglib/flac/flacfile.h @@ -318,6 +318,15 @@ namespace TagLib { */ bool hasID3v2Tag() const; + /*! + * Returns whether or not the given \a stream can be opened as a FLAC + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/mp4/mp4file.cpp b/taglib/mp4/mp4file.cpp index 3733fb40..f06ae068 100644 --- a/taglib/mp4/mp4file.cpp +++ b/taglib/mp4/mp4file.cpp @@ -26,6 +26,8 @@ #include #include #include +#include + #include "mp4atom.h" #include "mp4tag.h" #include "mp4file.h" @@ -69,6 +71,22 @@ public: MP4::Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool MP4::File::isValidStream(IOStream *stream) +{ + // An MP4 file has to have an "ftyp" box first. + + const ByteVector id = Utils::readHeader(stream, 8, false); + return id.containsAt("ftyp", 4); +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) : TagLib::File(file), d(new FilePrivate()) diff --git a/taglib/mp4/mp4file.h b/taglib/mp4/mp4file.h index 3840bd02..ca2f70de 100644 --- a/taglib/mp4/mp4file.h +++ b/taglib/mp4/mp4file.h @@ -120,6 +120,15 @@ namespace TagLib { */ bool hasMP4Tag() const; + /*! + * Returns whether or not the given \a stream can be opened as an ASF + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: void read(bool readProperties); diff --git a/taglib/mpc/mpcfile.cpp b/taglib/mpc/mpcfile.cpp index daf24c8f..b8544bb8 100644 --- a/taglib/mpc/mpcfile.cpp +++ b/taglib/mpc/mpcfile.cpp @@ -75,6 +75,19 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool MPC::File::isValidStream(IOStream *stream) +{ + // A newer MPC file has to start with "MPCK" or "MP+", but older files don't + // have keys to do a quick check. + + const ByteVector id = Utils::readHeader(stream, 4, false); + return (id == "MPCK" || id.startsWith("MP+")); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/mpc/mpcfile.h b/taglib/mpc/mpcfile.h index 541724dc..43759ea5 100644 --- a/taglib/mpc/mpcfile.h +++ b/taglib/mpc/mpcfile.h @@ -214,6 +214,15 @@ namespace TagLib { */ bool hasAPETag() const; + /*! + * Returns whether or not the given \a stream can be opened as an MPC + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/mpeg/mpegfile.cpp b/taglib/mpeg/mpegfile.cpp index 74bf779b..74f304f8 100644 --- a/taglib/mpeg/mpegfile.cpp +++ b/taglib/mpeg/mpegfile.cpp @@ -76,6 +76,63 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +namespace +{ + // Dummy file class to make a stream work with MPEG::Header. + + class AdapterFile : public TagLib::File + { + public: + AdapterFile(IOStream *stream) : File(stream) {} + + Tag *tag() const { return 0; } + AudioProperties *audioProperties() const { return 0; } + bool save() { return false; } + }; +} + +bool MPEG::File::isValidStream(IOStream *stream) +{ + if(!stream || !stream->isOpen()) + return false; + + // An MPEG file has MPEG frame headers. An ID3v2 tag may precede. + + // MPEG frame headers are really confusing with irrelevant binary data. + // So we check if a frame header is really valid. + + const long originalPosition = stream->tell(); + + long bufferOffset = 0; + + stream->seek(0); + const ByteVector data = stream->readBlock(ID3v2::Header::size()); + if(data.startsWith(ID3v2::Header::fileIdentifier())) + bufferOffset = ID3v2::Header(data).completeTagSize(); + + stream->seek(bufferOffset); + const ByteVector buffer = stream->readBlock(bufferSize()); + + AdapterFile file(stream); + + for(unsigned int i = 0; i < buffer.size() - 1; ++i) { + if(isFrameSync(buffer, i)) { + const Header header(&file, bufferOffset + i, true); + if(header.isValid()) { + stream->seek(originalPosition); + return true; + } + } + } + + stream->seek(originalPosition); + return false; +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/mpeg/mpegfile.h b/taglib/mpeg/mpegfile.h index e9e97387..71410fe7 100644 --- a/taglib/mpeg/mpegfile.h +++ b/taglib/mpeg/mpegfile.h @@ -370,6 +370,15 @@ namespace TagLib { */ bool hasAPETag() const; + /*! + * Returns whether or not the given \a stream can be opened as an MPEG + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/mpeg/mpegheader.cpp b/taglib/mpeg/mpegheader.cpp index 610b0320..5a5015d6 100644 --- a/taglib/mpeg/mpegheader.cpp +++ b/taglib/mpeg/mpegheader.cpp @@ -197,10 +197,8 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) d->version = Version2; else if(versionBits == 3) d->version = Version1; - else { - debug("MPEG::Header::parse() -- Invalid MPEG version bits."); + else return; - } // Set the MPEG layer @@ -212,10 +210,8 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) d->layer = 2; else if(layerBits == 3) d->layer = 1; - else { - debug("MPEG::Header::parse() -- Invalid MPEG layer bits."); + else return; - } d->protectionEnabled = (static_cast(data[1] & 0x01) == 0); @@ -244,10 +240,8 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) d->bitrate = bitrates[versionIndex][layerIndex][bitrateIndex]; - if(d->bitrate == 0) { - debug("MPEG::Header::parse() -- Invalid bit rate."); + if(d->bitrate == 0) return; - } // Set the sample rate @@ -264,7 +258,6 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) d->sampleRate = sampleRates[d->version][samplerateIndex]; if(d->sampleRate == 0) { - debug("MPEG::Header::parse() -- Invalid sample rate."); return; } @@ -311,20 +304,16 @@ void MPEG::Header::parse(File *file, long offset, bool checkLength) file->seek(offset + d->frameLength); const ByteVector nextData = file->readBlock(4); - if(nextData.size() < 4) { - debug("MPEG::Header::parse() -- Could not read the next frame header."); + if(nextData.size() < 4) return; - } const unsigned int HeaderMask = 0xfffe0c00; const unsigned int header = data.toUInt(0, true) & HeaderMask; const unsigned int nextHeader = nextData.toUInt(0, true) & HeaderMask; - if(header != nextHeader) { - debug("MPEG::Header::parse() -- The next frame was not consistent with this frame."); + if(header != nextHeader) return; - } } // Now that we're done parsing, set this to be a valid frame. diff --git a/taglib/mpeg/mpegutils.h b/taglib/mpeg/mpegutils.h index 1cee918a..31b45a43 100644 --- a/taglib/mpeg/mpegutils.h +++ b/taglib/mpeg/mpegutils.h @@ -45,12 +45,12 @@ namespace TagLib * \note This does not check the length of the vector, since this is an * internal utility function. */ - inline bool isFrameSync(const ByteVector &bytes) + inline bool isFrameSync(const ByteVector &bytes, unsigned int offset = 0) { // 0xFF in the second byte is possible in theory, but it's very unlikely. - const unsigned char b1 = bytes[0]; - const unsigned char b2 = bytes[1]; + const unsigned char b1 = bytes[offset + 0]; + const unsigned char b2 = bytes[offset + 1]; return (b1 == 0xFF && b2 != 0xFF && (b2 & 0xE0) == 0xE0); } diff --git a/taglib/ogg/flac/oggflacfile.cpp b/taglib/ogg/flac/oggflacfile.cpp index fe4d8830..e294d411 100644 --- a/taglib/ogg/flac/oggflacfile.cpp +++ b/taglib/ogg/flac/oggflacfile.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "oggflacfile.h" @@ -65,6 +66,18 @@ public: int commentPacket; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool Ogg::FLAC::File::isValidStream(IOStream *stream) +{ + // An Ogg FLAC file has IDs "OggS" and "fLaC" somewhere. + + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), false); + return (buffer.find("OggS") >= 0 && buffer.find("fLaC") >= 0); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/ogg/flac/oggflacfile.h b/taglib/ogg/flac/oggflacfile.h index 05762f9b..5f4313da 100644 --- a/taglib/ogg/flac/oggflacfile.h +++ b/taglib/ogg/flac/oggflacfile.h @@ -143,6 +143,14 @@ namespace TagLib { */ bool hasXiphComment() const; + /*! + * Check if the given \a stream can be opened as an Ogg FLAC file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/ogg/opus/opusfile.cpp b/taglib/ogg/opus/opusfile.cpp index ff1bfe2d..85d995bc 100644 --- a/taglib/ogg/opus/opusfile.cpp +++ b/taglib/ogg/opus/opusfile.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "opusfile.h" @@ -53,6 +54,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool Ogg::Opus::File::isValidStream(IOStream *stream) +{ + // An Opus file has IDs "OggS" and "OpusHead" somewhere. + + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), false); + return (buffer.find("OggS") >= 0 && buffer.find("OpusHead") >= 0); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/ogg/opus/opusfile.h b/taglib/ogg/opus/opusfile.h index b718f0d7..60f60c3f 100644 --- a/taglib/ogg/opus/opusfile.h +++ b/taglib/ogg/opus/opusfile.h @@ -113,6 +113,15 @@ namespace TagLib { */ virtual bool save(); + /*! + * Returns whether or not the given \a stream can be opened as an Opus + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/ogg/speex/speexfile.cpp b/taglib/ogg/speex/speexfile.cpp index 7af71d50..d3368774 100644 --- a/taglib/ogg/speex/speexfile.cpp +++ b/taglib/ogg/speex/speexfile.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "speexfile.h" @@ -53,6 +54,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool Ogg::Speex::File::isValidStream(IOStream *stream) +{ + // A Speex file has IDs "OggS" and "Speex " somewhere. + + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), false); + return (buffer.find("OggS") >= 0 && buffer.find("Speex ") >= 0); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/ogg/speex/speexfile.h b/taglib/ogg/speex/speexfile.h index 58b001dd..eda347e0 100644 --- a/taglib/ogg/speex/speexfile.h +++ b/taglib/ogg/speex/speexfile.h @@ -113,6 +113,15 @@ namespace TagLib { */ virtual bool save(); + /*! + * Returns whether or not the given \a stream can be opened as a Speex + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/ogg/vorbis/vorbisfile.cpp b/taglib/ogg/vorbis/vorbisfile.cpp index 2773bd3b..7f02fff5 100644 --- a/taglib/ogg/vorbis/vorbisfile.cpp +++ b/taglib/ogg/vorbis/vorbisfile.cpp @@ -28,10 +28,10 @@ #include #include #include +#include #include "vorbisfile.h" - using namespace TagLib; class Vorbis::File::FilePrivate @@ -59,6 +59,18 @@ namespace TagLib { static const char vorbisCommentHeaderID[] = { 0x03, 'v', 'o', 'r', 'b', 'i', 's', 0 }; } +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool Vorbis::File::isValidStream(IOStream *stream) +{ + // An Ogg Vorbis file has IDs "OggS" and "\x01vorbis" somewhere. + + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), false); + return (buffer.find("OggS") >= 0 && buffer.find("\x01vorbis") >= 0); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/ogg/vorbis/vorbisfile.h b/taglib/ogg/vorbis/vorbisfile.h index 9e71dcbe..9f7cb7e4 100644 --- a/taglib/ogg/vorbis/vorbisfile.h +++ b/taglib/ogg/vorbis/vorbisfile.h @@ -121,6 +121,14 @@ namespace TagLib { */ virtual bool save(); + /*! + * Check if the given \a stream can be opened as an Ogg Vorbis file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/riff/aiff/aifffile.cpp b/taglib/riff/aiff/aifffile.cpp index 1a29938c..72705a9a 100644 --- a/taglib/riff/aiff/aifffile.cpp +++ b/taglib/riff/aiff/aifffile.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "aifffile.h" @@ -53,6 +54,18 @@ public: bool hasID3v2; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool RIFF::AIFF::File::isValidStream(IOStream *stream) +{ + // An AIFF file has to start with "FORM????AIFF" or "FORM????AIFC". + + const ByteVector id = Utils::readHeader(stream, 12, false); + return (id.startsWith("FORM") && (id.containsAt("AIFF", 8) || id.containsAt("AIFC", 8))); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/riff/aiff/aifffile.h b/taglib/riff/aiff/aifffile.h index a79d76b2..611b7338 100644 --- a/taglib/riff/aiff/aifffile.h +++ b/taglib/riff/aiff/aifffile.h @@ -126,6 +126,14 @@ namespace TagLib { */ bool hasID3v2Tag() const; + /*! + * Check if the given \a stream can be opened as an AIFF file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/riff/wav/wavfile.cpp b/taglib/riff/wav/wavfile.cpp index 79ff9167..5e92b29e 100644 --- a/taglib/riff/wav/wavfile.cpp +++ b/taglib/riff/wav/wavfile.cpp @@ -23,10 +23,11 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include "tbytevector.h" -#include "tdebug.h" -#include "tstringlist.h" -#include "tpropertymap.h" +#include +#include +#include +#include +#include #include "wavfile.h" #include "id3v2tag.h" @@ -60,6 +61,18 @@ public: bool hasInfo; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool RIFF::WAV::File::isValidStream(IOStream *stream) +{ + // A WAV file has to start with "RIFF????WAVE". + + const ByteVector id = Utils::readHeader(stream, 12, false); + return (id.startsWith("RIFF") && id.containsAt("WAVE", 8)); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/riff/wav/wavfile.h b/taglib/riff/wav/wavfile.h index 80f17a85..47e8116d 100644 --- a/taglib/riff/wav/wavfile.h +++ b/taglib/riff/wav/wavfile.h @@ -175,6 +175,15 @@ namespace TagLib { */ bool hasInfoTag() const; + /*! + * Returns whether or not the given \a stream can be opened as a WAV + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/tagutils.cpp b/taglib/tagutils.cpp index dc047040..e27fd8bd 100644 --- a/taglib/tagutils.cpp +++ b/taglib/tagutils.cpp @@ -77,3 +77,25 @@ long Utils::findAPE(File *file, long id3v1Location) return -1; } + +ByteVector TagLib::Utils::readHeader(IOStream *stream, unsigned int length, bool skipID3v2) +{ + if(!stream || !stream->isOpen()) + return ByteVector(); + + const long originalPosition = stream->tell(); + long bufferOffset = 0; + + if(skipID3v2) { + stream->seek(0); + const ByteVector data = stream->readBlock(ID3v2::Header::size()); + if(data.startsWith(ID3v2::Header::fileIdentifier())) + bufferOffset = ID3v2::Header(data).completeTagSize(); + } + + stream->seek(bufferOffset); + const ByteVector header = stream->readBlock(length); + stream->seek(originalPosition); + + return header; +} diff --git a/taglib/tagutils.h b/taglib/tagutils.h index fb11d1e0..4014c673 100644 --- a/taglib/tagutils.h +++ b/taglib/tagutils.h @@ -30,9 +30,12 @@ #ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header +#include + namespace TagLib { class File; + class IOStream; namespace Utils { @@ -41,6 +44,8 @@ namespace TagLib { long findID3v2(File *file); long findAPE(File *file, long id3v1Location); + + ByteVector readHeader(IOStream *stream, unsigned int length, bool skipID3v2); } } diff --git a/taglib/trueaudio/trueaudiofile.cpp b/taglib/trueaudio/trueaudiofile.cpp index fc123ba3..c9b62bd7 100644 --- a/taglib/trueaudio/trueaudiofile.cpp +++ b/taglib/trueaudio/trueaudiofile.cpp @@ -73,6 +73,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool TrueAudio::File::isValidStream(IOStream *stream) +{ + // A TrueAudio file has to start with "TTA". An ID3v2 tag may precede. + + const ByteVector id = Utils::readHeader(stream, 3, true); + return (id == "TTA"); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/trueaudio/trueaudiofile.h b/taglib/trueaudio/trueaudiofile.h index 4bcb722a..c5b05d9f 100644 --- a/taglib/trueaudio/trueaudiofile.h +++ b/taglib/trueaudio/trueaudiofile.h @@ -235,6 +235,15 @@ namespace TagLib { */ bool hasID3v2Tag() const; + /*! + * Returns whether or not the given \a stream can be opened as a TrueAudio + * file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/taglib/wavpack/wavpackfile.cpp b/taglib/wavpack/wavpackfile.cpp index ef92f4bd..03f5ee07 100644 --- a/taglib/wavpack/wavpackfile.cpp +++ b/taglib/wavpack/wavpackfile.cpp @@ -71,6 +71,18 @@ public: Properties *properties; }; +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool WavPack::File::isValidStream(IOStream *stream) +{ + // A WavPack file has to start with "wvpk". + + const ByteVector id = Utils::readHeader(stream, 4, false); + return (id == "wvpk"); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/wavpack/wavpackfile.h b/taglib/wavpack/wavpackfile.h index 7e0bd27a..14bc823b 100644 --- a/taglib/wavpack/wavpackfile.h +++ b/taglib/wavpack/wavpackfile.h @@ -200,6 +200,14 @@ namespace TagLib { */ bool hasAPETag() const; + /*! + * Check if the given \a stream can be opened as a WavPack file. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isValidStream(IOStream *stream); + private: File(const File &); File &operator=(const File &); diff --git a/tests/test_fileref.cpp b/tests/test_fileref.cpp index 1b899975..c0d171be 100644 --- a/tests/test_fileref.cpp +++ b/tests/test_fileref.cpp @@ -1,27 +1,27 @@ /*************************************************************************** - copyright : (C) 2007 by Lukas Lalinsky - email : lukas@oxygene.sk - ***************************************************************************/ +copyright : (C) 2007 by Lukas Lalinsky +email : lukas@oxygene.sk +***************************************************************************/ /*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ +* This library is free software; you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License version * +* 2.1 as published by the Free Software Foundation. * +* * +* This library is distributed in the hope that it will be useful, but * +* WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with this library; if not, write to the Free Software * +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * +* 02110-1301 USA * +* * +* Alternatively, this file is available under the Mozilla Public * +* License Version 1.1. You may obtain a copy of the License at * +* http://www.mozilla.org/MPL/ * +***************************************************************************/ #include #include @@ -39,9 +39,10 @@ #include #include #include +#include +#include #include #include "utils.h" -#include using namespace std; using namespace TagLib; @@ -129,6 +130,7 @@ public: CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); } + { FileStream fs(newname.c_str()); FileRef f(&fs); @@ -140,6 +142,64 @@ public: CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("ialbummmm")); CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); + f.tag()->setArtist("test artist"); + f.tag()->setTitle("test title"); + f.tag()->setGenre("Test!"); + f.tag()->setAlbum("albummmm"); + f.tag()->setTrack(5); + f.tag()->setYear(2020); + f.save(); + } + + ByteVector fileContent; + { + FileStream fs(newname.c_str()); + FileRef f(&fs); + CPPUNIT_ASSERT(dynamic_cast(f.file())); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("test artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("test title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("Test!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("albummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)5); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2020); + + fs.seek(0); + fileContent = fs.readBlock(fs.length()); + } + + { + ByteVectorStream bs(fileContent); + FileRef f(&bs); + CPPUNIT_ASSERT(dynamic_cast(f.file())); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("test artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("test title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("Test!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("albummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)5); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2020); + f.tag()->setArtist("ttest artist"); + f.tag()->setTitle("ytest title"); + f.tag()->setGenre("uTest!"); + f.tag()->setAlbum("ialbummmm"); + f.tag()->setTrack(7); + f.tag()->setYear(2080); + f.save(); + + fileContent = *bs.data(); + } + { + ByteVectorStream bs(fileContent); + FileRef f(&bs); + CPPUNIT_ASSERT(dynamic_cast(f.file())); + CPPUNIT_ASSERT(!f.isNull()); + CPPUNIT_ASSERT_EQUAL(f.tag()->artist(), String("ttest artist")); + CPPUNIT_ASSERT_EQUAL(f.tag()->title(), String("ytest title")); + CPPUNIT_ASSERT_EQUAL(f.tag()->genre(), String("uTest!")); + CPPUNIT_ASSERT_EQUAL(f.tag()->album(), String("ialbummmm")); + CPPUNIT_ASSERT_EQUAL(f.tag()->track(), (unsigned int)7); + CPPUNIT_ASSERT_EQUAL(f.tag()->year(), (unsigned int)2080); } } From d4d8410c081d910891e4d8821bb46c06482d297e Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Sat, 4 Feb 2017 23:45:15 +0900 Subject: [PATCH 2/8] Restore the layout of the copyright header of test_fileref.cpp. --- tests/test_fileref.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/test_fileref.cpp b/tests/test_fileref.cpp index c0d171be..ee2d48d8 100644 --- a/tests/test_fileref.cpp +++ b/tests/test_fileref.cpp @@ -1,27 +1,27 @@ /*************************************************************************** -copyright : (C) 2007 by Lukas Lalinsky -email : lukas@oxygene.sk -***************************************************************************/ + copyright : (C) 2007 by Lukas Lalinsky + email : lukas@oxygene.sk + ***************************************************************************/ /*************************************************************************** -* This library is free software; you can redistribute it and/or modify * -* it under the terms of the GNU Lesser General Public License version * -* 2.1 as published by the Free Software Foundation. * -* * -* This library is distributed in the hope that it will be useful, but * -* WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * -* Lesser General Public License for more details. * -* * -* You should have received a copy of the GNU Lesser General Public * -* License along with this library; if not, write to the Free Software * -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * -* 02110-1301 USA * -* * -* Alternatively, this file is available under the Mozilla Public * -* License Version 1.1. You may obtain a copy of the License at * -* http://www.mozilla.org/MPL/ * -***************************************************************************/ + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ #include #include From f7b15fad2036f61ecb919dfd69e3455c4d501ad5 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 6 Feb 2017 10:35:49 +0900 Subject: [PATCH 3/8] Remove some redundant code. --- taglib/mpeg/mpegfile.cpp | 16 ++++------------ taglib/tagutils.cpp | 6 +++++- taglib/tagutils.h | 3 ++- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/taglib/mpeg/mpegfile.cpp b/taglib/mpeg/mpegfile.cpp index 74f304f8..adfcaac3 100644 --- a/taglib/mpeg/mpegfile.cpp +++ b/taglib/mpeg/mpegfile.cpp @@ -105,23 +105,15 @@ bool MPEG::File::isValidStream(IOStream *stream) // MPEG frame headers are really confusing with irrelevant binary data. // So we check if a frame header is really valid. + long headerOffset; + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true, &headerOffset); + const long originalPosition = stream->tell(); - - long bufferOffset = 0; - - stream->seek(0); - const ByteVector data = stream->readBlock(ID3v2::Header::size()); - if(data.startsWith(ID3v2::Header::fileIdentifier())) - bufferOffset = ID3v2::Header(data).completeTagSize(); - - stream->seek(bufferOffset); - const ByteVector buffer = stream->readBlock(bufferSize()); - AdapterFile file(stream); for(unsigned int i = 0; i < buffer.size() - 1; ++i) { if(isFrameSync(buffer, i)) { - const Header header(&file, bufferOffset + i, true); + const Header header(&file, headerOffset + i, true); if(header.isValid()) { stream->seek(originalPosition); return true; diff --git a/taglib/tagutils.cpp b/taglib/tagutils.cpp index e27fd8bd..d6d92406 100644 --- a/taglib/tagutils.cpp +++ b/taglib/tagutils.cpp @@ -78,7 +78,8 @@ long Utils::findAPE(File *file, long id3v1Location) return -1; } -ByteVector TagLib::Utils::readHeader(IOStream *stream, unsigned int length, bool skipID3v2) +ByteVector TagLib::Utils::readHeader(IOStream *stream, unsigned int length, + bool skipID3v2, long *headerOffset) { if(!stream || !stream->isOpen()) return ByteVector(); @@ -97,5 +98,8 @@ ByteVector TagLib::Utils::readHeader(IOStream *stream, unsigned int length, bool const ByteVector header = stream->readBlock(length); stream->seek(originalPosition); + if(headerOffset) + *headerOffset = bufferOffset; + return header; } diff --git a/taglib/tagutils.h b/taglib/tagutils.h index 4014c673..4488a32b 100644 --- a/taglib/tagutils.h +++ b/taglib/tagutils.h @@ -45,7 +45,8 @@ namespace TagLib { long findAPE(File *file, long id3v1Location); - ByteVector readHeader(IOStream *stream, unsigned int length, bool skipID3v2); + ByteVector readHeader(IOStream *stream, unsigned int length, bool skipID3v2, + long *headerOffset = 0); } } From f76b1e54296a71ec52664ebb411a2ba127ede67d Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 7 Feb 2017 22:36:56 +0900 Subject: [PATCH 4/8] Rename the functions 'isValidStream' to 'isSupported'. The name 'isValidStream' is a little misleading because it doesn't check if the stream is really valid. Additionally, 'isSupported' can be naturally overloaded. --- taglib/ape/apefile.cpp | 2 +- taglib/ape/apefile.h | 2 +- taglib/asf/asffile.cpp | 2 +- taglib/asf/asffile.h | 2 +- taglib/fileref.cpp | 30 +++++++++++++++--------------- taglib/flac/flacfile.cpp | 2 +- taglib/flac/flacfile.h | 2 +- taglib/mp4/mp4file.cpp | 2 +- taglib/mp4/mp4file.h | 2 +- taglib/mpc/mpcfile.cpp | 2 +- taglib/mpc/mpcfile.h | 2 +- taglib/mpeg/mpegfile.cpp | 2 +- taglib/mpeg/mpegfile.h | 2 +- taglib/ogg/flac/oggflacfile.cpp | 2 +- taglib/ogg/flac/oggflacfile.h | 2 +- taglib/ogg/opus/opusfile.cpp | 2 +- taglib/ogg/opus/opusfile.h | 2 +- taglib/ogg/speex/speexfile.cpp | 2 +- taglib/ogg/speex/speexfile.h | 2 +- taglib/ogg/vorbis/vorbisfile.cpp | 2 +- taglib/ogg/vorbis/vorbisfile.h | 2 +- taglib/riff/aiff/aifffile.cpp | 2 +- taglib/riff/aiff/aifffile.h | 2 +- taglib/riff/wav/wavfile.cpp | 2 +- taglib/riff/wav/wavfile.h | 2 +- taglib/trueaudio/trueaudiofile.cpp | 2 +- taglib/trueaudio/trueaudiofile.h | 2 +- taglib/wavpack/wavpackfile.cpp | 2 +- taglib/wavpack/wavpackfile.h | 2 +- 29 files changed, 43 insertions(+), 43 deletions(-) diff --git a/taglib/ape/apefile.cpp b/taglib/ape/apefile.cpp index fb01e4a2..a10c1f64 100644 --- a/taglib/ape/apefile.cpp +++ b/taglib/ape/apefile.cpp @@ -87,7 +87,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool APE::File::isValidStream(IOStream *stream) +bool APE::File::isSupported(IOStream *stream) { // An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede. diff --git a/taglib/ape/apefile.h b/taglib/ape/apefile.h index a7c870b4..267778ba 100644 --- a/taglib/ape/apefile.h +++ b/taglib/ape/apefile.h @@ -218,7 +218,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/asf/asffile.cpp b/taglib/asf/asffile.cpp index c209a640..d5a80bca 100644 --- a/taglib/asf/asffile.cpp +++ b/taglib/asf/asffile.cpp @@ -478,7 +478,7 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in // static members //////////////////////////////////////////////////////////////////////////////// -bool ASF::File::isValidStream(IOStream *stream) +bool ASF::File::isSupported(IOStream *stream) { // An ASF file has to start with the designated GUID. diff --git a/taglib/asf/asffile.h b/taglib/asf/asffile.h index 7df5a797..05cf4ee2 100644 --- a/taglib/asf/asffile.h +++ b/taglib/asf/asffile.h @@ -122,7 +122,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: void read(); diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index cad1ae50..d5df2a11 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -146,36 +146,36 @@ namespace { File *file = 0; - if(MPEG::File::isValidStream(stream)) + if(MPEG::File::isSupported(stream)) file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); - else if(Ogg::Vorbis::File::isValidStream(stream)) + else if(Ogg::Vorbis::File::isSupported(stream)) file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle); - else if(Ogg::FLAC::File::isValidStream(stream)) + else if(Ogg::FLAC::File::isSupported(stream)) file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle); - else if(FLAC::File::isValidStream(stream)) + else if(FLAC::File::isSupported(stream)) file = new FLAC::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle); - else if(MPC::File::isValidStream(stream)) + else if(MPC::File::isSupported(stream)) file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle); - else if(WavPack::File::isValidStream(stream)) + else if(WavPack::File::isSupported(stream)) file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle); - else if(Ogg::Speex::File::isValidStream(stream)) + else if(Ogg::Speex::File::isSupported(stream)) file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle); - else if(Ogg::Opus::File::isValidStream(stream)) + else if(Ogg::Opus::File::isSupported(stream)) file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle); - else if(TrueAudio::File::isValidStream(stream)) + else if(TrueAudio::File::isSupported(stream)) file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle); - else if(MP4::File::isValidStream(stream)) + else if(MP4::File::isSupported(stream)) file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle); - else if(ASF::File::isValidStream(stream)) + else if(ASF::File::isSupported(stream)) file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle); - else if(RIFF::AIFF::File::isValidStream(stream)) + else if(RIFF::AIFF::File::isSupported(stream)) file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle); - else if(RIFF::WAV::File::isValidStream(stream)) + else if(RIFF::WAV::File::isSupported(stream)) file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle); - else if(APE::File::isValidStream(stream)) + else if(APE::File::isSupported(stream)) file = new APE::File(stream, readAudioProperties, audioPropertiesStyle); - // isValidStream() only does a quick check, so double check the file here. + // isSupported() only does a quick check, so double check the file here. if(file) { if(file->isValid()) diff --git a/taglib/flac/flacfile.cpp b/taglib/flac/flacfile.cpp index 780ab1c3..7f437194 100644 --- a/taglib/flac/flacfile.cpp +++ b/taglib/flac/flacfile.cpp @@ -99,7 +99,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool FLAC::File::isValidStream(IOStream *stream) +bool FLAC::File::isSupported(IOStream *stream) { // A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede. diff --git a/taglib/flac/flacfile.h b/taglib/flac/flacfile.h index 56755ec5..645090e0 100644 --- a/taglib/flac/flacfile.h +++ b/taglib/flac/flacfile.h @@ -325,7 +325,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/mp4/mp4file.cpp b/taglib/mp4/mp4file.cpp index f06ae068..5ad8396d 100644 --- a/taglib/mp4/mp4file.cpp +++ b/taglib/mp4/mp4file.cpp @@ -75,7 +75,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool MP4::File::isValidStream(IOStream *stream) +bool MP4::File::isSupported(IOStream *stream) { // An MP4 file has to have an "ftyp" box first. diff --git a/taglib/mp4/mp4file.h b/taglib/mp4/mp4file.h index ca2f70de..8a46d17d 100644 --- a/taglib/mp4/mp4file.h +++ b/taglib/mp4/mp4file.h @@ -127,7 +127,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: void read(bool readProperties); diff --git a/taglib/mpc/mpcfile.cpp b/taglib/mpc/mpcfile.cpp index b8544bb8..0ffaf893 100644 --- a/taglib/mpc/mpcfile.cpp +++ b/taglib/mpc/mpcfile.cpp @@ -79,7 +79,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool MPC::File::isValidStream(IOStream *stream) +bool MPC::File::isSupported(IOStream *stream) { // A newer MPC file has to start with "MPCK" or "MP+", but older files don't // have keys to do a quick check. diff --git a/taglib/mpc/mpcfile.h b/taglib/mpc/mpcfile.h index 43759ea5..89a866e3 100644 --- a/taglib/mpc/mpcfile.h +++ b/taglib/mpc/mpcfile.h @@ -221,7 +221,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/mpeg/mpegfile.cpp b/taglib/mpeg/mpegfile.cpp index 74f304f8..75478ed8 100644 --- a/taglib/mpeg/mpegfile.cpp +++ b/taglib/mpeg/mpegfile.cpp @@ -95,7 +95,7 @@ namespace }; } -bool MPEG::File::isValidStream(IOStream *stream) +bool MPEG::File::isSupported(IOStream *stream) { if(!stream || !stream->isOpen()) return false; diff --git a/taglib/mpeg/mpegfile.h b/taglib/mpeg/mpegfile.h index 71410fe7..2d2dff00 100644 --- a/taglib/mpeg/mpegfile.h +++ b/taglib/mpeg/mpegfile.h @@ -377,7 +377,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/ogg/flac/oggflacfile.cpp b/taglib/ogg/flac/oggflacfile.cpp index e294d411..53d04508 100644 --- a/taglib/ogg/flac/oggflacfile.cpp +++ b/taglib/ogg/flac/oggflacfile.cpp @@ -70,7 +70,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool Ogg::FLAC::File::isValidStream(IOStream *stream) +bool Ogg::FLAC::File::isSupported(IOStream *stream) { // An Ogg FLAC file has IDs "OggS" and "fLaC" somewhere. diff --git a/taglib/ogg/flac/oggflacfile.h b/taglib/ogg/flac/oggflacfile.h index 5f4313da..b2686e45 100644 --- a/taglib/ogg/flac/oggflacfile.h +++ b/taglib/ogg/flac/oggflacfile.h @@ -149,7 +149,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/ogg/opus/opusfile.cpp b/taglib/ogg/opus/opusfile.cpp index 85d995bc..d4f191ad 100644 --- a/taglib/ogg/opus/opusfile.cpp +++ b/taglib/ogg/opus/opusfile.cpp @@ -58,7 +58,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool Ogg::Opus::File::isValidStream(IOStream *stream) +bool Ogg::Opus::File::isSupported(IOStream *stream) { // An Opus file has IDs "OggS" and "OpusHead" somewhere. diff --git a/taglib/ogg/opus/opusfile.h b/taglib/ogg/opus/opusfile.h index 60f60c3f..0e094eae 100644 --- a/taglib/ogg/opus/opusfile.h +++ b/taglib/ogg/opus/opusfile.h @@ -120,7 +120,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/ogg/speex/speexfile.cpp b/taglib/ogg/speex/speexfile.cpp index d3368774..b3c8a636 100644 --- a/taglib/ogg/speex/speexfile.cpp +++ b/taglib/ogg/speex/speexfile.cpp @@ -58,7 +58,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool Ogg::Speex::File::isValidStream(IOStream *stream) +bool Ogg::Speex::File::isSupported(IOStream *stream) { // A Speex file has IDs "OggS" and "Speex " somewhere. diff --git a/taglib/ogg/speex/speexfile.h b/taglib/ogg/speex/speexfile.h index eda347e0..1be7113c 100644 --- a/taglib/ogg/speex/speexfile.h +++ b/taglib/ogg/speex/speexfile.h @@ -120,7 +120,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/ogg/vorbis/vorbisfile.cpp b/taglib/ogg/vorbis/vorbisfile.cpp index 7f02fff5..b4f221ab 100644 --- a/taglib/ogg/vorbis/vorbisfile.cpp +++ b/taglib/ogg/vorbis/vorbisfile.cpp @@ -63,7 +63,7 @@ namespace TagLib { // static members //////////////////////////////////////////////////////////////////////////////// -bool Vorbis::File::isValidStream(IOStream *stream) +bool Vorbis::File::isSupported(IOStream *stream) { // An Ogg Vorbis file has IDs "OggS" and "\x01vorbis" somewhere. diff --git a/taglib/ogg/vorbis/vorbisfile.h b/taglib/ogg/vorbis/vorbisfile.h index 9f7cb7e4..04c0c04e 100644 --- a/taglib/ogg/vorbis/vorbisfile.h +++ b/taglib/ogg/vorbis/vorbisfile.h @@ -127,7 +127,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/riff/aiff/aifffile.cpp b/taglib/riff/aiff/aifffile.cpp index 72705a9a..4f9c868e 100644 --- a/taglib/riff/aiff/aifffile.cpp +++ b/taglib/riff/aiff/aifffile.cpp @@ -58,7 +58,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool RIFF::AIFF::File::isValidStream(IOStream *stream) +bool RIFF::AIFF::File::isSupported(IOStream *stream) { // An AIFF file has to start with "FORM????AIFF" or "FORM????AIFC". diff --git a/taglib/riff/aiff/aifffile.h b/taglib/riff/aiff/aifffile.h index 611b7338..5ba1a279 100644 --- a/taglib/riff/aiff/aifffile.h +++ b/taglib/riff/aiff/aifffile.h @@ -132,7 +132,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/riff/wav/wavfile.cpp b/taglib/riff/wav/wavfile.cpp index 5e92b29e..0ebe21c3 100644 --- a/taglib/riff/wav/wavfile.cpp +++ b/taglib/riff/wav/wavfile.cpp @@ -65,7 +65,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool RIFF::WAV::File::isValidStream(IOStream *stream) +bool RIFF::WAV::File::isSupported(IOStream *stream) { // A WAV file has to start with "RIFF????WAVE". diff --git a/taglib/riff/wav/wavfile.h b/taglib/riff/wav/wavfile.h index 47e8116d..f6c190ed 100644 --- a/taglib/riff/wav/wavfile.h +++ b/taglib/riff/wav/wavfile.h @@ -182,7 +182,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/trueaudio/trueaudiofile.cpp b/taglib/trueaudio/trueaudiofile.cpp index c9b62bd7..e4de436e 100644 --- a/taglib/trueaudio/trueaudiofile.cpp +++ b/taglib/trueaudio/trueaudiofile.cpp @@ -77,7 +77,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool TrueAudio::File::isValidStream(IOStream *stream) +bool TrueAudio::File::isSupported(IOStream *stream) { // A TrueAudio file has to start with "TTA". An ID3v2 tag may precede. diff --git a/taglib/trueaudio/trueaudiofile.h b/taglib/trueaudio/trueaudiofile.h index c5b05d9f..3737ac63 100644 --- a/taglib/trueaudio/trueaudiofile.h +++ b/taglib/trueaudio/trueaudiofile.h @@ -242,7 +242,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); diff --git a/taglib/wavpack/wavpackfile.cpp b/taglib/wavpack/wavpackfile.cpp index 03f5ee07..01bdba36 100644 --- a/taglib/wavpack/wavpackfile.cpp +++ b/taglib/wavpack/wavpackfile.cpp @@ -75,7 +75,7 @@ public: // static members //////////////////////////////////////////////////////////////////////////////// -bool WavPack::File::isValidStream(IOStream *stream) +bool WavPack::File::isSupported(IOStream *stream) { // A WavPack file has to start with "wvpk". diff --git a/taglib/wavpack/wavpackfile.h b/taglib/wavpack/wavpackfile.h index 14bc823b..ccc4ef6e 100644 --- a/taglib/wavpack/wavpackfile.h +++ b/taglib/wavpack/wavpackfile.h @@ -206,7 +206,7 @@ namespace TagLib { * \note This method is designed to do a quick check. The result may * not necessarily be correct. */ - static bool isValidStream(IOStream *stream); + static bool isSupported(IOStream *stream); private: File(const File &); From 682ea77c2bb63da79b61e0dd972367eaeecc6f15 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Wed, 31 May 2017 09:41:41 +0900 Subject: [PATCH 5/8] Mention that FileRef::create no longer works. --- NEWS | 1 + taglib/fileref.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ac22cd93..f8136f9a 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ * Fixed possible file corruptions when saving Ogg files. * Fixed reading FLAC files with zero-sized seektables. * Better handling of invalid UTF-8 sequences. + * Marked FileRef::create() deprecated. It returns null. * Several smaller bug fixes and performance improvements. TagLib 1.11.1 (Oct 24, 2016) diff --git a/taglib/fileref.h b/taglib/fileref.h index c36f54cb..ff14924e 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -268,7 +268,7 @@ namespace TagLib { * \note You generally shouldn't use this method, but instead the constructor * directly. * - * \deprecated + * \deprecated Always returns null. */ static File *create(FileName fileName, bool readAudioProperties = true, From c2fe93c12b70f3ae5604564558144282af1e48c2 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Tue, 6 Jun 2017 09:17:34 +0900 Subject: [PATCH 6/8] Restore FileRef::create() in order not to change the previous behavior. --- taglib/fileref.cpp | 74 +++++++++++++++++++++++++++++++++++++++++- taglib/fileref.h | 2 +- tests/test_fileref.cpp | 14 ++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index d5df2a11..935c371b 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -186,6 +186,78 @@ namespace return 0; } + + // 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) + { + File *file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle); + if(file) + 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 0; + + 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. */ + File *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); + + return 0; + } } class FileRef::FileRefPrivate : public RefCounter @@ -350,7 +422,7 @@ bool FileRef::operator!=(const FileRef &ref) const File *FileRef::create(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) // static { - return 0; + return createInternal(fileName, readAudioProperties, audioPropertiesStyle); } //////////////////////////////////////////////////////////////////////////////// diff --git a/taglib/fileref.h b/taglib/fileref.h index ff14924e..c36f54cb 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -268,7 +268,7 @@ namespace TagLib { * \note You generally shouldn't use this method, but instead the constructor * directly. * - * \deprecated Always returns null. + * \deprecated */ static File *create(FileName fileName, bool readAudioProperties = true, diff --git a/tests/test_fileref.cpp b/tests/test_fileref.cpp index ee2d48d8..e766a891 100644 --- a/tests/test_fileref.cpp +++ b/tests/test_fileref.cpp @@ -80,6 +80,7 @@ class TestFileRef : public CppUnit::TestFixture CPPUNIT_TEST(testAIFF_1); CPPUNIT_TEST(testAIFF_2); CPPUNIT_TEST(testUnsupported); + CPPUNIT_TEST(testCreate); CPPUNIT_TEST(testFileResolver); CPPUNIT_TEST_SUITE_END(); @@ -297,6 +298,19 @@ public: CPPUNIT_ASSERT(f2.isNull()); } + void testCreate() + { + // This is depricated. But worth it to test. + + File *f = FileRef::create(TEST_FILE_PATH_C("empty_vorbis.oga")); + CPPUNIT_ASSERT(dynamic_cast(f)); + delete f; + + f = FileRef::create(TEST_FILE_PATH_C("xing.mp3")); + CPPUNIT_ASSERT(dynamic_cast(f)); + delete f; + } + void testFileResolver() { { From c8bcd153fe4a1c9c792dd8cd404226b19a3fc1c7 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Fri, 9 Jun 2017 17:52:56 +0900 Subject: [PATCH 7/8] TableOfContentsFrame depends on ByteVectorList. --- taglib/mpeg/id3v2/frames/tableofcontentsframe.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/taglib/mpeg/id3v2/frames/tableofcontentsframe.h b/taglib/mpeg/id3v2/frames/tableofcontentsframe.h index 31196b2e..2e5401e8 100644 --- a/taglib/mpeg/id3v2/frames/tableofcontentsframe.h +++ b/taglib/mpeg/id3v2/frames/tableofcontentsframe.h @@ -29,6 +29,8 @@ #include "id3v2tag.h" #include "id3v2frame.h" +#include "tbytevectorlist.h" + namespace TagLib { namespace ID3v2 { From 1792ee9db81ed46fbce258c57a709ac7b38ea753 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Mon, 12 Jun 2017 13:07:21 +0900 Subject: [PATCH 8/8] Update NEWS. --- NEWS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 4a7abb56..9c97fb45 100644 --- a/NEWS +++ b/NEWS @@ -2,14 +2,15 @@ * Added support for WinRT. * Added support for classical music tags of iTunes 12.5. + * Enabled FileRef to detect file types based on the stream content. * Dropped support for Windows 9x and NT 4.0 or older. * Fixed reading MP4 atoms with zero length. * Fixed reading FLAC files with zero-sized seektables. * Fixed handling of lowercase field names in Vorbis Comments. * Fixed handling of 'rate' atoms in MP4 files. + * Fixed handling of invalid UTF-8 sequences. * Fixed possible file corruptions when saving Ogg files. - * Better handling of invalid UTF-8 sequences. - * Marked FileRef::create() deprecated. It returns null. + * Marked FileRef::create() deprecated. * Several smaller bug fixes and performance improvements. TagLib 1.11.1 (Oct 24, 2016)