Merge branch 'master' into merge-master-to-taglib2

# Conflicts:
#	taglib/ape/apefile.cpp
#	taglib/ape/apefile.h
#	taglib/fileref.cpp
#	taglib/flac/flacfile.cpp
#	taglib/flac/flacfile.h
#	taglib/mpc/mpcfile.cpp
#	taglib/mpc/mpcfile.h
#	taglib/mpeg/id3v2/frames/synchronizedlyricsframe.cpp
#	taglib/mpeg/id3v2/id3v2frame.cpp
#	taglib/tagunion.cpp
#	taglib/toolkit/tiostream.cpp
#	taglib/trueaudio/trueaudiofile.cpp
#	taglib/trueaudio/trueaudiofile.h
#	taglib/wavpack/wavpackfile.cpp
#	taglib/wavpack/wavpackfile.h
#	tests/test_fileref.cpp
#	tests/test_id3v2.cpp
This commit is contained in:
Tsuda Kageyu
2015-11-21 20:22:07 +09:00
51 changed files with 460 additions and 403 deletions

2
NEWS
View File

@ -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.

View File

@ -362,6 +362,7 @@ set(tag_LIB_SRCS
tagunion.cpp
fileref.cpp
audioproperties.cpp
tagutils.cpp
)
add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})

View File

@ -38,9 +38,9 @@
#include <id3v1tag.h>
#include <id3v2header.h>
#include <tpropertymap.h>
#include <tagutils.h>
#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;
}

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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]);

View File

@ -27,10 +27,10 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "tfile.h"
#include "tstring.h"
#include "tdebug.h"
#include "tsmartptr.h"
#include <tfile.h>
#include <tstring.h>
#include <tdebug.h>
#include <tsmartptr.h>
#include "fileref.h"
#include "asffile.h"
@ -58,91 +58,129 @@ using namespace TagLib;
namespace
{
typedef List<const FileRef::FileTypeResolver *> ResolverList;
typedef ResolverList::ConstIterator ResolverConstIterator;
ResolverList fileTypeResolvers;
SHARED_PTR<File> create(
FileName fileName,
bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
// Templatized internal functions. T should be String or IOStream*.
template <typename T>
inline FileName toFileName(T arg)
{
SHARED_PTR<File> 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 *>(IOStream *arg)
{
return arg->name();
}
template <>
inline FileName toFileName<FileName>(FileName arg)
{
return arg;
}
template <typename T>
inline File *resolveFileType(T arg, bool readProperties,
AudioProperties::ReadStyle style)
{
// Should never be called.
}
template <>
inline File *resolveFileType<IOStream *>(IOStream *arg, bool readProperties,
AudioProperties::ReadStyle style)
{
return 0;
}
template <>
inline File *resolveFileType<FileName>(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 <typename T>
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);
}

View File

@ -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.
*/

View File

@ -29,6 +29,7 @@
#include <tdebug.h>
#include <tagunion.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include <id3v2header.h>
#include <id3v2tag.h>
@ -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;
}

View File

@ -257,8 +257,6 @@ namespace TagLib {
void read(bool readProperties);
void scan();
offset_t findID3v2();
offset_t findID3v1();
class FilePrivate;
FilePrivate *d;

View File

@ -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);
}

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -28,6 +28,7 @@
#include <tagunion.h>
#include <tdebug.h>
#include <tpropertymap.h>
#include <tagutils.h>
#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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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);
}
}
}
}

View File

@ -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);

View File

@ -214,7 +214,7 @@ void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id)
String TableOfContentsFrame::toString() const
{
return String::null;
return String();
}
PropertyMap TableOfContentsFrame::asProperties() const

View File

@ -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());
}

View File

@ -86,7 +86,7 @@ void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v)
String UniqueFileIdentifierFrame::toString() const
{
return String::null;
return String();
}
PropertyMap UniqueFileIdentifierFrame::asProperties() const

View File

@ -51,7 +51,7 @@ UnknownFrame::~UnknownFrame()
String UnknownFrame::toString() const
{
return String::null;
return String();
}
ByteVector UnknownFrame::data() const

View File

@ -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);
}
}
}
}

View File

@ -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;

View File

@ -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)

View File

@ -504,7 +504,7 @@ void FrameFactory::updateGenre(TextIdentificationFrame *frame) const
}
if(newfields.isEmpty())
fields.append(String::null);
fields.append(String());
frame->setText(newfields);

View File

@ -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<TextIdentificationFrame *>(d->frameListMap["TCON"].front()))
{
return String::null;
return String();
}
// ID3v2.4 lists genres as the fields in its frames field list. If the field

View File

@ -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)

View File

@ -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);
}

View File

@ -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;

View File

@ -23,10 +23,10 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "tagunion.h"
#include "tstringlist.h"
#include "tpropertymap.h"
#include "tsmartptr.h"
#include <tagunion.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tsmartptr.h>
#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) { \

79
taglib/tagutils.cpp Normal file
View File

@ -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 <tfile.h>
#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;
}

49
taglib/tagutils.h Normal file
View File

@ -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

View File

@ -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<wchar_t> 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();
}
}

View File

@ -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())

View File

@ -33,6 +33,7 @@
#include <tagunion.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tagutils.h>
#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;
}

View File

@ -231,8 +231,6 @@ namespace TagLib {
File &operator=(const File &);
void read(bool readProperties);
offset_t findID3v1();
offset_t findID3v2();
class FilePrivate;
FilePrivate *d;

View File

@ -32,6 +32,7 @@
#include <tdebug.h>
#include <tagunion.h>
#include <tpropertymap.h>
#include <tagutils.h>
#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;
}

View File

@ -199,8 +199,6 @@ namespace TagLib {
File &operator=(const File &);
void read(bool readProperties);
offset_t findID3v1();
offset_t findAPE();
class FilePrivate;
FilePrivate *d;

View File

@ -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);
}

View File

@ -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");

View File

@ -4,12 +4,26 @@
#include <fileref.h>
#include <oggflacfile.h>
#include <vorbisfile.h>
#include <mpegfile.h>
#include <cppunit/extensions/HelperMacros.h>
#include "utils.h"
#include <tfilestream.h>
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<MPEG::File *>(f->file()) != NULL);
delete f;
DummyResolver resolver;
FileRef::addFileTypeResolver(&resolver);
f = new FileRef(TEST_FILE_PATH_C("xing.mp3"));
CPPUNIT_ASSERT(dynamic_cast<Ogg::Vorbis::File *>(f->file()) != NULL);
delete f;
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestFileRef);

View File

@ -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(); }
};

View File

@ -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());

View File

@ -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());

View File

@ -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());

View File

@ -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);

View File

@ -1,5 +1,6 @@
#include <string>
#include <stdio.h>
#include <flacfile.h>
#include <xiphcomment.h>
#include <tpropertymap.h>
#include <tdebug.h>
@ -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);

View File

@ -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());