diff --git a/NEWS b/NEWS index 1b3751bd..24d4525c 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,13 @@ ========================== + * New API for creating FileRef from IOStream. * Added support for ID3v2 PCST and WFED frames. * Added String::clear(). * Better handling of duplicate ID3v2 tags in all kinds of files. * Better handling of duplicate tags in WAV files. * Fixed crash when calling File::properties() after strip(). * Fixed possible file corruptions when saving ASF files. + * Fixed updating the comment field of Vorbis comments. * Marked ByteVector::null and ByteVector::isNull() deprecated. * Marked String::null and ByteVector::isNull() deprecated. * Many smaller bug fixes and performance improvements. diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt index 29624f2e..ed84805b 100644 --- a/taglib/CMakeLists.txt +++ b/taglib/CMakeLists.txt @@ -362,6 +362,7 @@ set(tag_LIB_SRCS tagunion.cpp fileref.cpp audioproperties.cpp + tagutils.cpp ) add_library(tag ${tag_LIB_SRCS} ${tag_HDRS}) diff --git a/taglib/ape/apefile.cpp b/taglib/ape/apefile.cpp index 232e0c2b..59510c12 100644 --- a/taglib/ape/apefile.cpp +++ b/taglib/ape/apefile.cpp @@ -38,9 +38,9 @@ #include #include #include +#include #include "apefile.h" - #include "apetag.h" #include "apefooter.h" @@ -248,7 +248,7 @@ void APE::File::read(bool readProperties) { // Look for an ID3v2 tag - d->ID3v2Location = findID3v2(); + d->ID3v2Location = Utils::findID3v2(this); if(d->ID3v2Location >= 0) { seek(d->ID3v2Location); @@ -259,7 +259,7 @@ void APE::File::read(bool readProperties) // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); if(d->ID3v1Location >= 0) { d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); @@ -268,7 +268,7 @@ void APE::File::read(bool readProperties) // Look for an APE tag - d->APELocation = findAPE(); + d->APELocation = Utils::findAPE(this, d->ID3v1Location); if(d->APELocation >= 0) { d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation)); @@ -304,48 +304,3 @@ void APE::File::read(bool readProperties) d->properties = new AudioProperties(this, streamLength); } } - -offset_t APE::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - offset_t p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -offset_t APE::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - offset_t p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -offset_t APE::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff --git a/taglib/ape/apefile.h b/taglib/ape/apefile.h index 5620fc4f..c9c728ea 100644 --- a/taglib/ape/apefile.h +++ b/taglib/ape/apefile.h @@ -206,9 +206,6 @@ namespace TagLib { File &operator=(const File &); void read(bool readProperties); - offset_t findAPE(); - offset_t findID3v1(); - offset_t findID3v2(); class FilePrivate; FilePrivate *d; diff --git a/taglib/ape/apeitem.cpp b/taglib/ape/apeitem.cpp index 534fb102..51b1fccd 100644 --- a/taglib/ape/apeitem.cpp +++ b/taglib/ape/apeitem.cpp @@ -197,7 +197,7 @@ String APE::Item::toString() const if(d->type == Text && !isEmpty()) return d->text.front(); else - return String::null; + return String(); } bool APE::Item::isEmpty() const diff --git a/taglib/ape/apetag.cpp b/taglib/ape/apetag.cpp index baaad7c2..1d0f62b3 100644 --- a/taglib/ape/apetag.cpp +++ b/taglib/ape/apetag.cpp @@ -81,35 +81,35 @@ ByteVector APE::Tag::fileIdentifier() String APE::Tag::title() const { if(d->itemListMap["TITLE"].isEmpty()) - return String::null; + return String(); return d->itemListMap["TITLE"].values().toString(); } String APE::Tag::artist() const { if(d->itemListMap["ARTIST"].isEmpty()) - return String::null; + return String(); return d->itemListMap["ARTIST"].values().toString(); } String APE::Tag::album() const { if(d->itemListMap["ALBUM"].isEmpty()) - return String::null; + return String(); return d->itemListMap["ALBUM"].values().toString(); } String APE::Tag::comment() const { if(d->itemListMap["COMMENT"].isEmpty()) - return String::null; + return String(); return d->itemListMap["COMMENT"].values().toString(); } String APE::Tag::genre() const { if(d->itemListMap["GENRE"].isEmpty()) - return String::null; + return String(); return d->itemListMap["GENRE"].values().toString(); } @@ -188,7 +188,7 @@ PropertyMap APE::Tag::properties() const String tagName = it->first.upper(); // if the item is Binary or Locator, or if the key is an invalid string, // add to unsupportedData - if(it->second.type() != Item::Text || tagName.isNull()) + if(it->second.type() != Item::Text || tagName.isEmpty()) properties.unsupportedData().append(it->first); else { // Some tags need to be handled specially @@ -225,7 +225,7 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) for(; remIt != itemListMap().end(); ++remIt) { String key = remIt->first.upper(); // only remove if a) key is valid, b) type is text, c) key not contained in new properties - if(!key.isNull() && remIt->second.type() == APE::Item::Text && !properties.contains(key)) + if(!key.isEmpty() && remIt->second.type() == APE::Item::Text && !properties.contains(key)) toRemove.append(remIt->first); } diff --git a/taglib/asf/asftag.cpp b/taglib/asf/asftag.cpp index 5b61a024..ea9141a3 100644 --- a/taglib/asf/asftag.cpp +++ b/taglib/asf/asftag.cpp @@ -64,7 +64,7 @@ String ASF::Tag::album() const { if(d->attributeListMap.contains("WM/AlbumTitle")) return d->attributeListMap["WM/AlbumTitle"][0].toString(); - return String::null; + return String(); } String ASF::Tag::copyright() const @@ -107,7 +107,7 @@ String ASF::Tag::genre() const { if(d->attributeListMap.contains("WM/Genre")) return d->attributeListMap["WM/Genre"][0].toString(); - return String::null; + return String(); } void ASF::Tag::setTitle(const String &value) @@ -329,16 +329,16 @@ PropertyMap ASF::Tag::setProperties(const PropertyMap &props) for(; it != origProps.end(); ++it) { if(!props.contains(it->first) || props[it->first].isEmpty()) { if(it->first == "TITLE") { - d->title = String::null; + d->title.clear(); } else if(it->first == "ARTIST") { - d->artist = String::null; + d->artist.clear(); } else if(it->first == "COMMENT") { - d->comment = String::null; + d->comment.clear(); } else if(it->first == "COPYRIGHT") { - d->copyright = String::null; + d->copyright.clear(); } else { d->attributeListMap.erase(reverseKeyMap[it->first]); diff --git a/taglib/fileref.cpp b/taglib/fileref.cpp index 5d8c25de..eb3f5275 100644 --- a/taglib/fileref.cpp +++ b/taglib/fileref.cpp @@ -27,10 +27,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include "tfile.h" -#include "tstring.h" -#include "tdebug.h" -#include "tsmartptr.h" +#include +#include +#include +#include #include "fileref.h" #include "asffile.h" @@ -58,91 +58,129 @@ using namespace TagLib; namespace { typedef List ResolverList; - typedef ResolverList::ConstIterator ResolverConstIterator; - ResolverList fileTypeResolvers; - SHARED_PTR create( - FileName fileName, - bool readAudioProperties, - AudioProperties::ReadStyle audioPropertiesStyle) + // Templatized internal functions. T should be String or IOStream*. + + template + inline FileName toFileName(T arg) { - SHARED_PTR file; - for(ResolverConstIterator it = fileTypeResolvers.begin(); it != fileTypeResolvers.end(); ++it) - { - file.reset((*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle)); + // Should never be called. + } + + template <> + inline FileName toFileName(IOStream *arg) + { + return arg->name(); + } + + template <> + inline FileName toFileName(FileName arg) + { + return arg; + } + + template + inline File *resolveFileType(T arg, bool readProperties, + AudioProperties::ReadStyle style) + { + // Should never be called. + } + + template <> + inline File *resolveFileType(IOStream *arg, bool readProperties, + AudioProperties::ReadStyle style) + { + return 0; + } + + template <> + inline File *resolveFileType(FileName arg, bool readProperties, + AudioProperties::ReadStyle style) + { + ResolverList::ConstIterator it = fileTypeResolvers.begin(); + for(; it != fileTypeResolvers.end(); ++it) { + File *file = (*it)->createFile(arg, readProperties, style); if(file) return file; } - String ext; - { + return 0; + } + + template + File* createInternal(T arg, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) + { + File *file = resolveFileType(arg, readAudioProperties, audioPropertiesStyle); + if(file) + return file; + #ifdef _WIN32 - - String s = fileName.toString(); - + const String s = toFileName(arg).toString(); #else - - String s = fileName; - + const String s(toFileName(arg)); #endif - const size_t pos = s.rfind("."); - if(pos != String::npos()) - ext = s.substr(pos + 1).upper(); - } + String ext; + const int pos = s.rfind("."); + if(pos != -1) + ext = s.substr(pos + 1).upper(); // If this list is updated, the method defaultFileExtensions() should also be // updated. However at some point that list should be created at the same time // that a default file type resolver is created. - if(!ext.isEmpty()) { - if(ext == "MP3") - file.reset(new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "OGG") - file.reset(new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "OGA") { - /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ - file.reset(new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle)); - if(!file->isValid()) - file.reset(new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle)); - } - else if(ext == "FLAC") - file.reset(new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "MPC") - file.reset(new MPC::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "WV") - file.reset(new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "SPX") - file.reset(new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "OPUS") - file.reset(new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "TTA") - file.reset(new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2") - file.reset(new MP4::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "WMA" || ext == "ASF") - file.reset(new ASF::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC") - file.reset(new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "WAV") - file.reset(new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "APE") - file.reset(new APE::File(fileName, readAudioProperties, audioPropertiesStyle)); - // module, nst and wow are possible but uncommon extensions - else if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") - file.reset(new Mod::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "S3M") - file.reset(new S3M::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "IT") - file.reset(new IT::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "XM") - file.reset(new XM::File(fileName, readAudioProperties, audioPropertiesStyle)); - else if(ext == "DSF") - file.reset(new DSF::File(fileName, readAudioProperties, audioPropertiesStyle)); - } + if(ext.isEmpty()) + return 0; - return file; + if(ext == "MP3") + return new MPEG::File(arg, 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); + } + if(ext == "FLAC") + return new FLAC::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "MPC") + return new MPC::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "WV") + return new WavPack::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "SPX") + return new Ogg::Speex::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "OPUS") + return new Ogg::Opus::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "TTA") + return new TrueAudio::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2") + return new MP4::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "WMA" || ext == "ASF") + return new ASF::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC") + return new RIFF::AIFF::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "WAV") + return new RIFF::WAV::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "APE") + return new APE::File(arg, 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); + if(ext == "S3M") + return new S3M::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "IT") + return new IT::File(arg, readAudioProperties, audioPropertiesStyle); + if(ext == "XM") + return new XM::File(arg, readAudioProperties, audioPropertiesStyle); + if (ext == "DSF") + return new DSF::File(arg, readAudioProperties, audioPropertiesStyle); + + return 0; } } @@ -170,8 +208,14 @@ FileRef::FileRef() : { } -FileRef::FileRef(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle style) : - d(new FileRefPrivate(create(fileName, readAudioProperties, style))) +FileRef::FileRef(FileName fileName, bool readAudioProperties, + AudioProperties::ReadStyle audioPropertiesStyle) : + d(new FileRefPrivate(createInternal(fileName, readAudioProperties, audioPropertiesStyle))) +{ +} + +FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) : + d(new FileRefPrivate(createInternal(stream, readAudioProperties, audioPropertiesStyle))) { } @@ -306,16 +350,23 @@ bool FileRef::isNull() const FileRef &FileRef::operator=(const FileRef &ref) { - *d = *ref.d; + FileRef(ref).swap(*this); return *this; } +void FileRef::swap(FileRef &ref) +{ + using std::swap; + + swap(d, ref.d); +} + bool FileRef::operator==(const FileRef &ref) const { - return (d->file == ref.d->file); + return (ref.d->file == d->file); } bool FileRef::operator!=(const FileRef &ref) const { - return (d->file != ref.d->file); + return (ref.d->file != d->file); } diff --git a/taglib/fileref.h b/taglib/fileref.h index 0b149924..71126aba 100644 --- a/taglib/fileref.h +++ b/taglib/fileref.h @@ -128,6 +128,20 @@ namespace TagLib { AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average); + /*! + * Construct a FileRef from an opened \a IOStream. 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. + * + * Also see the note in the class documentation about why you may not want to + * use this method in your application. + */ + explicit FileRef(IOStream* stream, + bool readAudioProperties = true, + AudioProperties::ReadStyle + audioPropertiesStyle = AudioProperties::Average); + /*! * Construct a FileRef using \a file. The FileRef now takes ownership of the * pointer and will delete the File when it passes out of scope. @@ -271,6 +285,11 @@ namespace TagLib { */ FileRef &operator=(const FileRef &ref); + /*! + * Exchanges the content of the FileRef by the content of \a ref. + */ + void swap(FileRef &ref); + /*! * Returns true if this FileRef and \a ref point to the same File object. */ diff --git a/taglib/flac/flacfile.cpp b/taglib/flac/flacfile.cpp index faf1cc80..045dfdec 100644 --- a/taglib/flac/flacfile.cpp +++ b/taglib/flac/flacfile.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -330,7 +331,7 @@ void FLAC::File::read(bool readProperties) { // Look for an ID3v2 tag - d->ID3v2Location = findID3v2(); + d->ID3v2Location = Utils::findID3v2(this); if(d->ID3v2Location >= 0) { @@ -346,7 +347,7 @@ void FLAC::File::read(bool readProperties) // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); if(d->ID3v1Location >= 0) { d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); @@ -507,30 +508,3 @@ void FLAC::File::scan() d->scanned = true; } - -offset_t FLAC::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - offset_t p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -offset_t FLAC::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff --git a/taglib/flac/flacfile.h b/taglib/flac/flacfile.h index 002a3c5e..f17df67e 100644 --- a/taglib/flac/flacfile.h +++ b/taglib/flac/flacfile.h @@ -257,8 +257,6 @@ namespace TagLib { void read(bool readProperties); void scan(); - offset_t findID3v2(); - offset_t findID3v1(); class FilePrivate; FilePrivate *d; diff --git a/taglib/it/itfile.cpp b/taglib/it/itfile.cpp index e7f89dc2..6b7168fd 100644 --- a/taglib/it/itfile.cpp +++ b/taglib/it/itfile.cpp @@ -108,7 +108,7 @@ bool IT::File::save() if(i < lines.size()) writeString(lines[i], 25); else - writeString(String::null, 25); + writeString(String(), 25); writeByte(0); } @@ -123,7 +123,7 @@ bool IT::File::save() if((TagLib::uint)(i + instrumentCount) < lines.size()) writeString(lines[i + instrumentCount], 25); else - writeString(String::null, 25); + writeString(String(), 25); writeByte(0); } diff --git a/taglib/mod/modfile.cpp b/taglib/mod/modfile.cpp index b3fc176b..5872cad5 100644 --- a/taglib/mod/modfile.cpp +++ b/taglib/mod/modfile.cpp @@ -89,7 +89,7 @@ bool Mod::File::save() } for(uint i = n; i < d->properties.instrumentCount(); ++ i) { - writeString(String::null, 22); + writeString(String(), 22); seek(8, Current); } return true; diff --git a/taglib/mod/modtag.cpp b/taglib/mod/modtag.cpp index 4ba72117..af98fb92 100644 --- a/taglib/mod/modtag.cpp +++ b/taglib/mod/modtag.cpp @@ -55,12 +55,12 @@ String Mod::Tag::title() const String Mod::Tag::artist() const { - return String::null; + return String(); } String Mod::Tag::album() const { - return String::null; + return String(); } String Mod::Tag::comment() const @@ -70,7 +70,7 @@ String Mod::Tag::comment() const String Mod::Tag::genre() const { - return String::null; + return String(); } TagLib::uint Mod::Tag::year() const @@ -128,7 +128,7 @@ PropertyMap Mod::Tag::properties() const PropertyMap properties; properties["TITLE"] = d->title; properties["COMMENT"] = d->comment; - if(!(d->trackerName.isNull())) + if(!(d->trackerName.isEmpty())) properties["TRACKERNAME"] = d->trackerName; return properties; } @@ -142,19 +142,19 @@ PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps) d->title = properties["TITLE"].front(); oneValueSet.append("TITLE"); } else - d->title = String::null; + d->title.clear(); if(properties.contains("COMMENT")) { d->comment = properties["COMMENT"].front(); oneValueSet.append("COMMENT"); } else - d->comment = String::null; + d->comment.clear(); if(properties.contains("TRACKERNAME")) { d->trackerName = properties["TRACKERNAME"].front(); oneValueSet.append("TRACKERNAME"); } else - d->trackerName = String::null; + d->trackerName.clear(); // for each tag that has been set above, remove the first entry in the corresponding // value list. The others will be returned as unsupported by this format. diff --git a/taglib/mp4/mp4tag.cpp b/taglib/mp4/mp4tag.cpp index 7d1dff6f..50f1a0fb 100644 --- a/taglib/mp4/mp4tag.cpp +++ b/taglib/mp4/mp4tag.cpp @@ -686,7 +686,7 @@ MP4::Tag::title() const { if(d->items.contains("\251nam")) return d->items["\251nam"].toStringList().toString(", "); - return String::null; + return String(); } String @@ -694,7 +694,7 @@ MP4::Tag::artist() const { if(d->items.contains("\251ART")) return d->items["\251ART"].toStringList().toString(", "); - return String::null; + return String(); } String @@ -702,7 +702,7 @@ MP4::Tag::album() const { if(d->items.contains("\251alb")) return d->items["\251alb"].toStringList().toString(", "); - return String::null; + return String(); } String @@ -710,7 +710,7 @@ MP4::Tag::comment() const { if(d->items.contains("\251cmt")) return d->items["\251cmt"].toStringList().toString(", "); - return String::null; + return String(); } String @@ -718,7 +718,7 @@ MP4::Tag::genre() const { if(d->items.contains("\251gen")) return d->items["\251gen"].toStringList().toString(", "); - return String::null; + return String(); } unsigned int diff --git a/taglib/mpc/mpcfile.cpp b/taglib/mpc/mpcfile.cpp index e24d7083..06cd2b2f 100644 --- a/taglib/mpc/mpcfile.cpp +++ b/taglib/mpc/mpcfile.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "mpcfile.h" #include "id3v1tag.h" @@ -256,7 +257,7 @@ void MPC::File::read(bool readProperties) { // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); if(d->ID3v1Location >= 0) { d->tag.set(MPCID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); @@ -265,7 +266,7 @@ void MPC::File::read(bool readProperties) // Look for an APE tag - d->APELocation = findAPE(); + d->APELocation = Utils::findAPE(this, d->ID3v1Location); if(d->APELocation >= 0) { d->tag.set(MPCAPEIndex, new APE::Tag(this, d->APELocation)); @@ -280,7 +281,7 @@ void MPC::File::read(bool readProperties) // Look for an ID3v2 tag - d->ID3v2Location = findID3v2(); + d->ID3v2Location = Utils::findID3v2(this); if(d->ID3v2Location >= 0) { seek(d->ID3v2Location); @@ -313,48 +314,3 @@ void MPC::File::read(bool readProperties) d->properties = new AudioProperties(this, streamLength); } } - -offset_t MPC::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - offset_t p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -offset_t MPC::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - offset_t p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -offset_t MPC::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff --git a/taglib/mpc/mpcfile.h b/taglib/mpc/mpcfile.h index 9cdaef1e..5ffdf0f3 100644 --- a/taglib/mpc/mpcfile.h +++ b/taglib/mpc/mpcfile.h @@ -213,9 +213,6 @@ namespace TagLib { File &operator=(const File &); void read(bool readProperties); - offset_t findAPE(); - offset_t findID3v1(); - offset_t findID3v2(); class FilePrivate; FilePrivate *d; diff --git a/taglib/mpeg/id3v1/id3v1tag.cpp b/taglib/mpeg/id3v1/id3v1tag.cpp index 39798745..06b49830 100644 --- a/taglib/mpeg/id3v1/id3v1tag.cpp +++ b/taglib/mpeg/id3v1/id3v1tag.cpp @@ -182,7 +182,7 @@ void ID3v1::Tag::setGenre(const String &s) void ID3v1::Tag::setYear(TagLib::uint i) { - d->year = i > 0 ? String::number(i) : String::null; + d->year = i > 0 ? String::number(i) : String(); } void ID3v1::Tag::setTrack(TagLib::uint i) diff --git a/taglib/mpeg/id3v2/frames/commentsframe.cpp b/taglib/mpeg/id3v2/frames/commentsframe.cpp index deaa9d9a..b5618322 100644 --- a/taglib/mpeg/id3v2/frames/commentsframe.cpp +++ b/taglib/mpeg/id3v2/frames/commentsframe.cpp @@ -116,8 +116,6 @@ PropertyMap CommentsFrame::asProperties() const PropertyMap map; if(key.isEmpty() || key == "COMMENT") map.insert("COMMENT", text()); - else if(key.isNull()) - map.unsupportedData().append(L"COMM/" + description()); else map.insert("COMMENT:" + key, text()); return map; @@ -164,7 +162,7 @@ void CommentsFrame::parseFields(const ByteVector &data) } else { d->description = String(l.front(), d->textEncoding); d->text = String(l.back(), d->textEncoding); - } + } } } diff --git a/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp b/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp index 2a4c6663..f00a39af 100644 --- a/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp +++ b/taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp @@ -159,7 +159,7 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data) size_t pos = 6; d->description = readStringField(data, d->textEncoding, pos); - if(d->description.isNull()) + if(d->description.isEmpty()) return; /* @@ -190,7 +190,7 @@ void SynchronizedLyricsFrame::parseFields(const ByteVector &data) } } String text = readStringField(data, enc, pos); - if(text.isNull() || pos + 4 > end) + if(text.isEmpty() || pos + 4 > end) return; uint time = data.toUInt32BE(pos); diff --git a/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp b/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp index a3598398..8d659cc5 100644 --- a/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp +++ b/taglib/mpeg/id3v2/frames/tableofcontentsframe.cpp @@ -214,7 +214,7 @@ void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id) String TableOfContentsFrame::toString() const { - return String::null; + return String(); } PropertyMap TableOfContentsFrame::asProperties() const diff --git a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp index d32ecc5f..7fc40a5f 100644 --- a/taglib/mpeg/id3v2/frames/textidentificationframe.cpp +++ b/taglib/mpeg/id3v2/frames/textidentificationframe.cpp @@ -295,7 +295,7 @@ PropertyMap TextIdentificationFrame::makeTMCLProperties() const StringList l = fieldList(); for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) { String instrument = it->upper(); - if(instrument.isNull()) { + if(instrument.isEmpty()) { // instrument is not a valid key -> frame unsupported map.clear(); map.unsupportedData().append(frameID()); @@ -315,8 +315,8 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) d(0) { StringList l; - l.append(String::null); - l.append(String::null); + l.append(String()); + l.append(String()); setText(l); } @@ -344,7 +344,7 @@ String UserTextIdentificationFrame::description() const { return !TextIdentificationFrame::fieldList().isEmpty() ? TextIdentificationFrame::fieldList().front() - : String::null; + : String(); } StringList UserTextIdentificationFrame::fieldList() const @@ -357,7 +357,7 @@ StringList UserTextIdentificationFrame::fieldList() const void UserTextIdentificationFrame::setText(const String &text) { if(description().isEmpty()) - setDescription(String::null); + setDescription(String()); TextIdentificationFrame::setText(StringList(description()).append(text)); } @@ -365,7 +365,7 @@ void UserTextIdentificationFrame::setText(const String &text) void UserTextIdentificationFrame::setText(const StringList &fields) { if(description().isEmpty()) - setDescription(String::null); + setDescription(String()); TextIdentificationFrame::setText(StringList(description()).append(fields)); } @@ -420,7 +420,7 @@ void UserTextIdentificationFrame::checkFields() const size_t fields = fieldList().size(); if(fields == 0) - setDescription(String::null); + setDescription(String()); if(fields <= 1) - setText(String::null); + setText(String()); } diff --git a/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp b/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp index 1d30b799..eef4e51e 100644 --- a/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp +++ b/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp @@ -86,7 +86,7 @@ void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v) String UniqueFileIdentifierFrame::toString() const { - return String::null; + return String(); } PropertyMap UniqueFileIdentifierFrame::asProperties() const diff --git a/taglib/mpeg/id3v2/frames/unknownframe.cpp b/taglib/mpeg/id3v2/frames/unknownframe.cpp index 4def028b..9d059193 100644 --- a/taglib/mpeg/id3v2/frames/unknownframe.cpp +++ b/taglib/mpeg/id3v2/frames/unknownframe.cpp @@ -51,7 +51,7 @@ UnknownFrame::~UnknownFrame() String UnknownFrame::toString() const { - return String::null; + return String(); } ByteVector UnknownFrame::data() const diff --git a/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp b/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp index 8f96cb8d..f97cdc5a 100644 --- a/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp +++ b/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp @@ -119,8 +119,6 @@ PropertyMap UnsynchronizedLyricsFrame::asProperties() const String key = description().upper(); if(key.isEmpty() || key.upper() == "LYRICS") map.insert("LYRICS", text()); - else if(key.isNull()) - map.unsupportedData().append(L"USLT/" + description()); else map.insert("LYRICS:" + key, text()); return map; @@ -164,7 +162,7 @@ void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data) } else { d->description = String(l.front(), d->textEncoding); d->text = String(l.back(), d->textEncoding); - } + } } } diff --git a/taglib/mpeg/id3v2/frames/urllinkframe.cpp b/taglib/mpeg/id3v2/frames/urllinkframe.cpp index 5bf48d5a..7852d103 100644 --- a/taglib/mpeg/id3v2/frames/urllinkframe.cpp +++ b/taglib/mpeg/id3v2/frames/urllinkframe.cpp @@ -159,8 +159,6 @@ PropertyMap UserUrlLinkFrame::asProperties() const String key = description().upper(); if(key.isEmpty() || key.upper() == "URL") map.insert("URL", url()); - else if(key.isNull()) - map.unsupportedData().append(L"WXXX/" + description()); else map.insert("URL:" + key, url()); return map; diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index a30501a5..bffd2550 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -311,7 +311,7 @@ String Frame::readStringField(const ByteVector &data, String::Type encoding, siz const size_t end = data.find(delimiter, position, delimiter.size()); if(end == ByteVector::npos() || end < position) - return String::null; + return String(); String str; if(encoding == String::Latin1) diff --git a/taglib/mpeg/id3v2/id3v2framefactory.cpp b/taglib/mpeg/id3v2/id3v2framefactory.cpp index 44da49c1..4c5d3af8 100644 --- a/taglib/mpeg/id3v2/id3v2framefactory.cpp +++ b/taglib/mpeg/id3v2/id3v2framefactory.cpp @@ -504,7 +504,7 @@ void FrameFactory::updateGenre(TextIdentificationFrame *frame) const } if(newfields.isEmpty()) - fields.append(String::null); + fields.append(String()); frame->setText(newfields); diff --git a/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/mpeg/id3v2/id3v2tag.cpp index 96ed8d02..dd32f2c7 100644 --- a/taglib/mpeg/id3v2/id3v2tag.cpp +++ b/taglib/mpeg/id3v2/id3v2tag.cpp @@ -139,21 +139,21 @@ String ID3v2::Tag::title() const { if(!d->frameListMap["TIT2"].isEmpty()) return d->frameListMap["TIT2"].front()->toString(); - return String::null; + return String(); } String ID3v2::Tag::artist() const { if(!d->frameListMap["TPE1"].isEmpty()) return d->frameListMap["TPE1"].front()->toString(); - return String::null; + return String(); } String ID3v2::Tag::album() const { if(!d->frameListMap["TALB"].isEmpty()) return d->frameListMap["TALB"].front()->toString(); - return String::null; + return String(); } String ID3v2::Tag::comment() const @@ -161,7 +161,7 @@ String ID3v2::Tag::comment() const const FrameList &comments = d->frameListMap["COMM"]; if(comments.isEmpty()) - return String::null; + return String(); for(FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) { @@ -183,7 +183,7 @@ String ID3v2::Tag::genre() const if(d->frameListMap["TCON"].isEmpty() || !dynamic_cast(d->frameListMap["TCON"].front())) { - return String::null; + return String(); } // ID3v2.4 lists genres as the fields in its frames field list. If the field diff --git a/taglib/ogg/xiphcomment.cpp b/taglib/ogg/xiphcomment.cpp index 64e05ac0..daf8181e 100644 --- a/taglib/ogg/xiphcomment.cpp +++ b/taglib/ogg/xiphcomment.cpp @@ -62,21 +62,21 @@ Ogg::XiphComment::~XiphComment() String Ogg::XiphComment::title() const { if(d->fieldListMap["TITLE"].isEmpty()) - return String::null; + return String(); return d->fieldListMap["TITLE"].toString(); } String Ogg::XiphComment::artist() const { if(d->fieldListMap["ARTIST"].isEmpty()) - return String::null; + return String(); return d->fieldListMap["ARTIST"].toString(); } String Ogg::XiphComment::album() const { if(d->fieldListMap["ALBUM"].isEmpty()) - return String::null; + return String(); return d->fieldListMap["ALBUM"].toString(); } @@ -92,13 +92,13 @@ String Ogg::XiphComment::comment() const return d->fieldListMap["COMMENT"].toString(); } - return String::null; + return String(); } String Ogg::XiphComment::genre() const { if(d->fieldListMap["GENRE"].isEmpty()) - return String::null; + return String(); return d->fieldListMap["GENRE"].toString(); } @@ -137,7 +137,14 @@ void Ogg::XiphComment::setAlbum(const String &s) void Ogg::XiphComment::setComment(const String &s) { - addField(d->commentField.isEmpty() ? "DESCRIPTION" : d->commentField, s); + if(d->commentField.isEmpty()) { + if(!d->fieldListMap["DESCRIPTION"].isEmpty()) + d->commentField = "DESCRIPTION"; + else + d->commentField = "COMMENT"; + } + + addField(d->commentField, s); } void Ogg::XiphComment::setGenre(const String &s) diff --git a/taglib/s3m/s3mfile.cpp b/taglib/s3m/s3mfile.cpp index dbd6654f..61a2d1d8 100644 --- a/taglib/s3m/s3mfile.cpp +++ b/taglib/s3m/s3mfile.cpp @@ -124,7 +124,7 @@ bool S3M::File::save() if(i < lines.size()) writeString(lines[i], 27); else - writeString(String::null, 27); + writeString(String(), 27); // string terminating NUL is not optional: writeByte(0); } diff --git a/taglib/tag.cpp b/taglib/tag.cpp index f4447a49..e4f5c933 100644 --- a/taglib/tag.cpp +++ b/taglib/tag.cpp @@ -58,15 +58,15 @@ bool Tag::isEmpty() const PropertyMap Tag::properties() const { PropertyMap map; - if(!(title().isNull())) + if(!(title().isEmpty())) map["TITLE"].append(title()); - if(!(artist().isNull())) + if(!(artist().isEmpty())) map["ARTIST"].append(artist()); - if(!(album().isNull())) + if(!(album().isEmpty())) map["ALBUM"].append(album()); - if(!(comment().isNull())) + if(!(comment().isEmpty())) map["COMMENT"].append(comment()); - if(!(genre().isNull())) + if(!(genre().isEmpty())) map["GENRE"].append(genre()); if(!(year() == 0)) map["DATE"].append(String::number(year())); @@ -89,31 +89,31 @@ PropertyMap Tag::setProperties(const PropertyMap &origProps) setTitle(properties["TITLE"].front()); oneValueSet.append("TITLE"); } else - setTitle(String::null); + setTitle(String()); if(properties.contains("ARTIST")) { setArtist(properties["ARTIST"].front()); oneValueSet.append("ARTIST"); } else - setArtist(String::null); + setArtist(String()); if(properties.contains("ALBUM")) { setAlbum(properties["ALBUM"].front()); oneValueSet.append("ALBUM"); } else - setAlbum(String::null); + setAlbum(String()); if(properties.contains("COMMENT")) { setComment(properties["COMMENT"].front()); oneValueSet.append("COMMENT"); } else - setComment(String::null); + setComment(String()); if(properties.contains("GENRE")) { setGenre(properties["GENRE"].front()); oneValueSet.append("GENRE"); } else - setGenre(String::null); + setGenre(String()); if(properties.contains("DATE")) { bool ok; diff --git a/taglib/tagunion.cpp b/taglib/tagunion.cpp index c47bc2c8..78cc62af 100644 --- a/taglib/tagunion.cpp +++ b/taglib/tagunion.cpp @@ -23,10 +23,10 @@ * http://www.mozilla.org/MPL/ * ***************************************************************************/ -#include "tagunion.h" -#include "tstringlist.h" -#include "tpropertymap.h" -#include "tsmartptr.h" +#include +#include +#include +#include #define stringUnion(method) \ for(size_t j = 0; j < COUNT; ++j) { \ @@ -34,7 +34,7 @@ if(!val.isEmpty()) \ return val; \ } \ - return String::null; + return String(); #define numberUnion(method) \ for(size_t j = 0; j < COUNT; ++j) { \ diff --git a/taglib/tagutils.cpp b/taglib/tagutils.cpp new file mode 100644 index 00000000..2c556ca7 --- /dev/null +++ b/taglib/tagutils.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + copyright : (C) 2015 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * 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 "id3v1tag.h" +#include "id3v2header.h" +#include "apetag.h" + +#include "tagutils.h" + +using namespace TagLib; + +offset_t Utils::findID3v1(File *file) +{ + if(!file->isValid()) + return -1; + + file->seek(-128, File::End); + const offset_t p = file->tell(); + + if(file->readBlock(3) == ID3v1::Tag::fileIdentifier()) + return p; + + return -1; +} + +offset_t Utils::findID3v2(File *file) +{ + if(!file->isValid()) + return -1; + + file->seek(0); + + if(file->readBlock(3) == ID3v2::Header::fileIdentifier()) + return 0; + + return -1; +} + +offset_t Utils::findAPE(File *file, offset_t id3v1Location) +{ + if(!file->isValid()) + return -1; + + if(id3v1Location >= 0) + file->seek(id3v1Location - 32, File::Beginning); + else + file->seek(-32, File::End); + + const offset_t p = file->tell(); + + if(file->readBlock(8) == APE::Tag::fileIdentifier()) + return p; + + return -1; +} diff --git a/taglib/tagutils.h b/taglib/tagutils.h new file mode 100644 index 00000000..0001f34b --- /dev/null +++ b/taglib/tagutils.h @@ -0,0 +1,49 @@ +/*************************************************************************** + copyright : (C) 2015 by Tsuda Kageyu + email : tsuda.kageyu@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * 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/ * + ***************************************************************************/ + +#ifndef TAGLIB_TAGUTILS_H +#define TAGLIB_TAGUTILS_H + +// THIS FILE IS NOT A PART OF THE TAGLIB API + +#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header + +namespace TagLib { + + class File; + + namespace Utils { + + offset_t findID3v1(File *file); + + offset_t findID3v2(File *file); + + offset_t findAPE(File *file, offset_t id3v1Location); + } +} + +#endif + +#endif diff --git a/taglib/toolkit/tiostream.cpp b/taglib/toolkit/tiostream.cpp index 80570cab..6c4c1b51 100644 --- a/taglib/toolkit/tiostream.cpp +++ b/taglib/toolkit/tiostream.cpp @@ -147,7 +147,7 @@ String FileName::toString() const else if(!d->data->name.empty()) { const int len = ::MultiByteToWideChar(CP_ACP, 0, d->data->name.c_str(), -1, NULL, 0); if(len == 0) - return String::null; + return String(); std::vector buf(len); ::MultiByteToWideChar(CP_ACP, 0, d->data->name.c_str(), -1, &buf[0], len); @@ -155,7 +155,7 @@ String FileName::toString() const return String(&buf[0]); } else { - return String::null; + return String(); } } diff --git a/taglib/toolkit/tpropertymap.cpp b/taglib/toolkit/tpropertymap.cpp index 313d7fb4..1c6a47d9 100644 --- a/taglib/toolkit/tpropertymap.cpp +++ b/taglib/toolkit/tpropertymap.cpp @@ -35,7 +35,7 @@ PropertyMap::PropertyMap(const SimplePropertyMap &m) { for(SimplePropertyMap::ConstIterator it = m.begin(); it != m.end(); ++it){ String key = it->first.upper(); - if(!key.isNull()) + if(!key.isEmpty()) insert(it->first, it->second); else unsupported.append(it->first); @@ -144,7 +144,8 @@ bool PropertyMap::operator!=(const PropertyMap &other) const String PropertyMap::toString() const { - String ret = ""; + String ret; + for(ConstIterator it = begin(); it != end(); ++it) ret += it->first+"="+it->second.toString(", ") + "\n"; if(!unsupported.isEmpty()) diff --git a/taglib/trueaudio/trueaudiofile.cpp b/taglib/trueaudio/trueaudiofile.cpp index a070f536..508d3a59 100644 --- a/taglib/trueaudio/trueaudiofile.cpp +++ b/taglib/trueaudio/trueaudiofile.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "trueaudiofile.h" #include "id3v1tag.h" @@ -240,7 +241,7 @@ void TrueAudio::File::read(bool readProperties) { // Look for an ID3v2 tag - d->ID3v2Location = findID3v2(); + d->ID3v2Location = Utils::findID3v2(this); if(d->ID3v2Location >= 0) { @@ -256,7 +257,7 @@ void TrueAudio::File::read(bool readProperties) // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); if(d->ID3v1Location >= 0) { d->tag.set(TrueAudioID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); @@ -288,30 +289,3 @@ void TrueAudio::File::read(bool readProperties) d->properties = new AudioProperties(readBlock(HeaderSize), streamLength); } } - -offset_t TrueAudio::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - offset_t p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -offset_t TrueAudio::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff --git a/taglib/trueaudio/trueaudiofile.h b/taglib/trueaudio/trueaudiofile.h index 70e66b04..1ea5790d 100644 --- a/taglib/trueaudio/trueaudiofile.h +++ b/taglib/trueaudio/trueaudiofile.h @@ -231,8 +231,6 @@ namespace TagLib { File &operator=(const File &); void read(bool readProperties); - offset_t findID3v1(); - offset_t findID3v2(); class FilePrivate; FilePrivate *d; diff --git a/taglib/wavpack/wavpackfile.cpp b/taglib/wavpack/wavpackfile.cpp index abc67917..2411ef08 100644 --- a/taglib/wavpack/wavpackfile.cpp +++ b/taglib/wavpack/wavpackfile.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "wavpackfile.h" #include "id3v1tag.h" @@ -233,7 +234,7 @@ void WavPack::File::read(bool readProperties) { // Look for an ID3v1 tag - d->ID3v1Location = findID3v1(); + d->ID3v1Location = Utils::findID3v1(this); if(d->ID3v1Location >= 0) { d->tag.set(WavID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); @@ -242,7 +243,7 @@ void WavPack::File::read(bool readProperties) // Look for an APE tag - d->APELocation = findAPE(); + d->APELocation = Utils::findAPE(this, d->ID3v1Location); if(d->APELocation >= 0) { d->tag.set(WavAPEIndex, new APE::Tag(this, d->APELocation)); @@ -270,35 +271,3 @@ void WavPack::File::read(bool readProperties) d->properties = new AudioProperties(this, streamLength); } } - -offset_t WavPack::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - offset_t p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -offset_t WavPack::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - offset_t p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} diff --git a/taglib/wavpack/wavpackfile.h b/taglib/wavpack/wavpackfile.h index ebed7a9d..88a83d0a 100644 --- a/taglib/wavpack/wavpackfile.h +++ b/taglib/wavpack/wavpackfile.h @@ -199,8 +199,6 @@ namespace TagLib { File &operator=(const File &); void read(bool readProperties); - offset_t findID3v1(); - offset_t findAPE(); class FilePrivate; FilePrivate *d; diff --git a/taglib/xm/xmfile.cpp b/taglib/xm/xmfile.cpp index 9cff50d5..01ccd5af 100644 --- a/taglib/xm/xmfile.cpp +++ b/taglib/xm/xmfile.cpp @@ -452,7 +452,7 @@ bool XM::File::save() seek(pos + 4); const uint len = std::min(22U, instrumentHeaderSize - 4U); if(i >= lines.size()) - writeString(String::null, len); + writeString(String(), len); else writeString(lines[i], len); @@ -483,7 +483,7 @@ bool XM::File::save() seek(pos + 18); const uint len = std::min(sampleHeaderSize - 18U, 22U); if(sampleNameIndex >= lines.size()) - writeString(String::null, len); + writeString(String(), len); else writeString(lines[sampleNameIndex ++], len); } diff --git a/tests/test_apetag.cpp b/tests/test_apetag.cpp index 72893c5b..3a4d853b 100644 --- a/tests/test_apetag.cpp +++ b/tests/test_apetag.cpp @@ -108,7 +108,7 @@ public: ByteVector data("Test Data"); item.setBinaryData(data); CPPUNIT_ASSERT(item.values().isEmpty()); - CPPUNIT_ASSERT_EQUAL(String::null, item.toString()); + CPPUNIT_ASSERT_EQUAL(String(), item.toString()); CPPUNIT_ASSERT_EQUAL(data, item.binaryData()); item.setValue("Test Text 2"); diff --git a/tests/test_fileref.cpp b/tests/test_fileref.cpp index cda44153..1e28d48f 100644 --- a/tests/test_fileref.cpp +++ b/tests/test_fileref.cpp @@ -4,12 +4,26 @@ #include #include #include +#include #include #include "utils.h" +#include using namespace std; using namespace TagLib; +namespace +{ + class DummyResolver : public FileRef::FileTypeResolver + { + public: + virtual File *createFile(FileName fileName, bool, AudioProperties::ReadStyle) const + { + return new Ogg::Vorbis::File(fileName); + } + }; +} + class TestFileRef : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestFileRef); @@ -30,6 +44,7 @@ class TestFileRef : public CppUnit::TestFixture CPPUNIT_TEST(testAIFF); CPPUNIT_TEST(testAIFC); CPPUNIT_TEST(testUnsupported); + CPPUNIT_TEST(testFileResolver); CPPUNIT_TEST_SUITE_END(); public: @@ -80,26 +95,16 @@ public: CPPUNIT_ASSERT_EQUAL(f->tag()->year(), TagLib::uint(2080)); delete f; - f = new FileRef(newname.c_str()); - CPPUNIT_ASSERT(f->isValid()); + FileStream fs(newname.c_str()); + f = new FileRef(&fs); CPPUNIT_ASSERT(!f->isNull()); - PropertyMap prop = f->properties(); - CPPUNIT_ASSERT_EQUAL(prop["ARTIST"].front(), String("ttest artist")); - CPPUNIT_ASSERT_EQUAL(prop["TITLE" ].front(), String("ytest title")); - prop["ARTIST"].front() = "a test artist"; - prop["TITLE" ].front() = "b test title"; - f->setProperties(prop); - f->save(); + 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(), TagLib::uint(7)); + CPPUNIT_ASSERT_EQUAL(f->tag()->year(), TagLib::uint(2080)); delete f; - - f = new FileRef(newname.c_str()); - CPPUNIT_ASSERT(f->isValid()); - CPPUNIT_ASSERT(!f->isNull()); - prop = f->properties(); - CPPUNIT_ASSERT_EQUAL(prop["ARTIST"].front(), String("a test artist")); - CPPUNIT_ASSERT_EQUAL(prop["TITLE" ].front(), String("b test title")); - delete f; - } void testMusepack() @@ -192,10 +197,25 @@ public: { FileRef f1(TEST_FILE_PATH_C("no-extension")); CPPUNIT_ASSERT(f1.isNull()); - + FileRef f2(TEST_FILE_PATH_C("unsupported-extension.xxx")); CPPUNIT_ASSERT(f2.isNull()); } + + void testFileResolver() + { + FileRef *f = new FileRef(TEST_FILE_PATH_C("xing.mp3")); + CPPUNIT_ASSERT(dynamic_cast(f->file()) != NULL); + delete f; + + DummyResolver resolver; + FileRef::addFileTypeResolver(&resolver); + + f = new FileRef(TEST_FILE_PATH_C("xing.mp3")); + CPPUNIT_ASSERT(dynamic_cast(f->file()) != NULL); + delete f; + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestFileRef); diff --git a/tests/test_id3v2.cpp b/tests/test_id3v2.cpp index 8e885541..0f8d0ac8 100644 --- a/tests/test_id3v2.cpp +++ b/tests/test_id3v2.cpp @@ -38,7 +38,7 @@ class PublicFrame : public ID3v2::Frame size_t position = 0; return ID3v2::Frame::readStringField(data, encoding, position); } - virtual String toString() const { return String::null; } + virtual String toString() const { return String(); } virtual void parseFields(const ByteVector &) {} virtual ByteVector renderFields() const { return ByteVector(); } }; diff --git a/tests/test_it.cpp b/tests/test_it.cpp index 68fd67b1..c5d16326 100644 --- a/tests/test_it.cpp +++ b/tests/test_it.cpp @@ -123,10 +123,10 @@ private: CPPUNIT_ASSERT_EQUAL((TagLib::uchar)128, p->panningSeparation()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 0, p->pitchWheelDepth()); CPPUNIT_ASSERT_EQUAL(title, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); CPPUNIT_ASSERT_EQUAL(comment, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(String("Impulse Tracker"), t->trackerName()); diff --git a/tests/test_mod.cpp b/tests/test_mod.cpp index 9120de91..e776d5a3 100644 --- a/tests/test_mod.cpp +++ b/tests/test_mod.cpp @@ -113,10 +113,10 @@ private: CPPUNIT_ASSERT_EQUAL(31U, p->instrumentCount()); CPPUNIT_ASSERT_EQUAL((uchar)1, p->lengthInPatterns()); CPPUNIT_ASSERT_EQUAL(title, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); CPPUNIT_ASSERT_EQUAL(comment, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(String("StarTrekker"), t->trackerName()); diff --git a/tests/test_s3m.cpp b/tests/test_s3m.cpp index 2b289ece..bbc0d0f9 100644 --- a/tests/test_s3m.cpp +++ b/tests/test_s3m.cpp @@ -110,10 +110,10 @@ private: CPPUNIT_ASSERT_EQUAL((TagLib::uchar)125, p->tempo()); CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 6, p->bpmSpeed()); CPPUNIT_ASSERT_EQUAL(title, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); CPPUNIT_ASSERT_EQUAL(comment, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(String("ScreamTracker III"), t->trackerName()); diff --git a/tests/test_string.cpp b/tests/test_string.cpp index 5afc32e5..32137cfe 100644 --- a/tests/test_string.cpp +++ b/tests/test_string.cpp @@ -75,7 +75,7 @@ public: s.clear(); CPPUNIT_ASSERT(s.isEmpty()); - CPPUNIT_ASSERT(!s.isNull()); + CPPUNIT_ASSERT(!s.isNull()); // deprecated, but still worth it to check. String unicode("José Carlos", String::UTF8); CPPUNIT_ASSERT(strcmp(unicode.toCString(), "Jos\xe9 Carlos") == 0); diff --git a/tests/test_xiphcomment.cpp b/tests/test_xiphcomment.cpp index 897bbac0..00ae4f56 100644 --- a/tests/test_xiphcomment.cpp +++ b/tests/test_xiphcomment.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -17,6 +18,7 @@ class TestXiphComment : public CppUnit::TestFixture CPPUNIT_TEST(testTrack); CPPUNIT_TEST(testSetTrack); CPPUNIT_TEST(testInvalidKeys); + CPPUNIT_TEST(testClearComment); CPPUNIT_TEST_SUITE_END(); public: @@ -74,6 +76,22 @@ public: CPPUNIT_ASSERT(cmt.properties().isEmpty()); } + void testClearComment() + { + ScopedFileCopy copy("no-tags", ".flac"); + + { + FLAC::File f(copy.fileName().c_str()); + f.xiphComment()->addField("COMMENT", "Comment1"); + f.save(); + } + { + FLAC::File f(copy.fileName().c_str()); + f.xiphComment()->setComment(""); + CPPUNIT_ASSERT_EQUAL(String(""), f.xiphComment()->comment()); + } + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(TestXiphComment); diff --git a/tests/test_xm.cpp b/tests/test_xm.cpp index a9a91d7f..6929e5ba 100644 --- a/tests/test_xm.cpp +++ b/tests/test_xm.cpp @@ -139,13 +139,13 @@ public: CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 6, p->tempo()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)125, p->bpmSpeed()); CPPUNIT_ASSERT_EQUAL(titleBefore, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); - CPPUNIT_ASSERT_EQUAL(String::null, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); + CPPUNIT_ASSERT_EQUAL(String(), t->comment()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); - CPPUNIT_ASSERT_EQUAL(String::null, t->trackerName()); + CPPUNIT_ASSERT_EQUAL(String(), t->trackerName()); } void testWriteTagsShort() @@ -185,10 +185,10 @@ private: CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 6, p->tempo()); CPPUNIT_ASSERT_EQUAL((TagLib::ushort)125, p->bpmSpeed()); CPPUNIT_ASSERT_EQUAL(title, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); + CPPUNIT_ASSERT_EQUAL(String(), t->artist()); + CPPUNIT_ASSERT_EQUAL(String(), t->album()); CPPUNIT_ASSERT_EQUAL(comment, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); + CPPUNIT_ASSERT_EQUAL(String(), t->genre()); CPPUNIT_ASSERT_EQUAL(0U, t->year()); CPPUNIT_ASSERT_EQUAL(0U, t->track()); CPPUNIT_ASSERT_EQUAL(trackerName, t->trackerName());