Merge remote-tracking branch 'correct/taglib2' into taglib2

This commit is contained in:
Sebastian Rachuj
2013-05-21 00:27:06 +02:00
48 changed files with 1782 additions and 1422 deletions

View File

@@ -11,7 +11,7 @@ Teemu Tervo <teemu.tervo@gmx.net>
Mathias Panzenböck <grosser.meister.morti@gmx.net>
Mod, S3M, IT and XM metadata implementations
Tsuda Kageyu <tsuda.kageyu@gmail.com>
A lot of minor improvements, such as large files support.
A lot of fixes and improvements, i.e. memory copy reduction, large files support, etc.
Please send all patches and questions to taglib-devel@kde.org rather than to
individual developers!

View File

@@ -213,7 +213,7 @@ check_cxx_source_compiles("
check_cxx_source_compiles("
#include <memory>
int main() { std::tr1::shared_ptr<int> x; return 0; }
int main() { std::shared_ptr<int> x; return 0; }
" TAGLIB_USE_STD_SHARED_PTR)
if(NOT TAGLIB_USE_STD_SHARED_PTR)
@@ -230,6 +230,20 @@ if(NOT TAGLIB_USE_STD_SHARED_PTR)
endif()
endif()
# Determine where unique_ptr<T> or scoped_ptr<T> is defined regardless of C++11 support.
check_cxx_source_compiles("
#include <memory>
int main() { std::unique_ptr<int> x; return 0; }
" TAGLIB_USE_STD_UNIQUE_PTR)
if(NOT TAGLIB_USE_STD_UNIQUE_PTR)
check_cxx_source_compiles("
#include <boost/scoped_ptr.hpp>
int main() { boost::scoped_ptr<int> x; return 0; }
" TAGLIB_USE_BOOST_SCOPED_PTR)
endif()
# Determine whether CppUnit is installed.
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)

View File

@@ -47,12 +47,12 @@ static bool stringManagementEnabled = true;
void taglib_set_strings_unicode(BOOL unicode)
{
unicodeStrings = bool(unicode);
unicodeStrings = (unicode != 0);
}
void taglib_set_string_management_enabled(BOOL management)
{
stringManagementEnabled = bool(management);
stringManagementEnabled = (management != 0);
}
void taglib_free(void* pointer)
@@ -66,32 +66,32 @@ void taglib_free(void* pointer)
TagLib_File *taglib_file_new(const char *filename)
{
return reinterpret_cast<TagLib_File *>(FileRef::create(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(filename));
}
TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
{
switch(type) {
case TagLib_File_MPEG:
return reinterpret_cast<TagLib_File *>(new MPEG::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new MPEG::File(filename)));
case TagLib_File_OggVorbis:
return reinterpret_cast<TagLib_File *>(new Ogg::Vorbis::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::Vorbis::File(filename)));
case TagLib_File_FLAC:
return reinterpret_cast<TagLib_File *>(new FLAC::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new FLAC::File(filename)));
case TagLib_File_MPC:
return reinterpret_cast<TagLib_File *>(new MPC::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new MPC::File(filename)));
case TagLib_File_OggFlac:
return reinterpret_cast<TagLib_File *>(new Ogg::FLAC::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::FLAC::File(filename)));
case TagLib_File_WavPack:
return reinterpret_cast<TagLib_File *>(new WavPack::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new WavPack::File(filename)));
case TagLib_File_Speex:
return reinterpret_cast<TagLib_File *>(new Ogg::Speex::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::Speex::File(filename)));
case TagLib_File_TrueAudio:
return reinterpret_cast<TagLib_File *>(new TrueAudio::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new TrueAudio::File(filename)));
case TagLib_File_MP4:
return reinterpret_cast<TagLib_File *>(new MP4::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new MP4::File(filename)));
case TagLib_File_ASF:
return reinterpret_cast<TagLib_File *>(new ASF::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new ASF::File(filename)));
default:
return 0;
}
@@ -101,29 +101,29 @@ TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
void taglib_file_free(TagLib_File *file)
{
delete reinterpret_cast<File *>(file);
delete reinterpret_cast<FileRef *>(file);
}
BOOL taglib_file_is_valid(const TagLib_File *file)
{
return reinterpret_cast<const File *>(file)->isValid();
return reinterpret_cast<const FileRef *>(file)->isValid();
}
TagLib_Tag *taglib_file_tag(const TagLib_File *file)
{
const File *f = reinterpret_cast<const File *>(file);
const FileRef *f = reinterpret_cast<const FileRef *>(file);
return reinterpret_cast<TagLib_Tag *>(f->tag());
}
const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file)
{
const File *f = reinterpret_cast<const File *>(file);
const FileRef *f = reinterpret_cast<const FileRef *>(file);
return reinterpret_cast<const TagLib_AudioProperties *>(f->audioProperties());
}
BOOL taglib_file_save(TagLib_File *file)
{
return reinterpret_cast<File *>(file)->save();
return reinterpret_cast<FileRef *>(file)->save();
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -54,7 +54,6 @@ set(tag_HDRS
toolkit/tmap.tcc
toolkit/tpropertymap.h
toolkit/tsmartptr.h
toolkit/trefcountptr.h
mpeg/mpegfile.h
mpeg/mpegproperties.h
mpeg/mpegheader.h
@@ -301,7 +300,7 @@ set(toolkit_SRCS
toolkit/tfilestream.cpp
toolkit/tdebug.cpp
toolkit/tpropertymap.cpp
toolkit/trefcountptr.cpp
toolkit/tsmartptr.cpp
toolkit/unicode.cpp
)

View File

@@ -175,14 +175,17 @@ void APE::Tag::setTrack(uint i)
addValue("TRACK", String::number(i), true);
}
// conversions of tag keys between what we use in PropertyMap and what's usual
// for APE tags
static const TagLib::uint keyConversionsSize = 5; //usual, APE
static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
{"DATE", "YEAR" },
{"ALBUMARTIST", "ALBUM ARTIST"},
{"DISCNUMBER", "DISC" },
{"REMIXER", "MIXARTIST" }};
namespace
{
// conversions of tag keys between what we use in PropertyMap and what's usual
// for APE tags
static const TagLib::uint keyConversionsSize = 5; //usual, APE
static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
{"DATE", "YEAR" },
{"ALBUMARTIST", "ALBUM ARTIST"},
{"DISCNUMBER", "DISC" },
{"REMIXER", "MIXARTIST" }};
}
PropertyMap APE::Tag::properties() const
{

View File

@@ -205,7 +205,7 @@ namespace TagLib
ByteVector render(const String &name, int kind = 0) const;
class AttributePrivate;
TAGLIB_SHARED_PTR<AttributePrivate> d;
RefCountPtr<AttributePrivate> d;
};
}

View File

@@ -56,17 +56,20 @@ public:
ASF::File::MetadataLibraryObject *metadataLibraryObject;
};
static const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
static const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
static const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
static const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
static const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
static const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
static const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
static const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
static const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
static const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
static const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
namespace
{
const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
}
class ASF::File::BaseObject
{

View File

@@ -231,7 +231,7 @@ namespace TagLib
#endif
private:
class PicturePrivate;
TAGLIB_SHARED_PTR<PicturePrivate> d;
RefCountPtr<PicturePrivate> d;
};
}
}

View File

@@ -194,46 +194,49 @@ bool ASF::Tag::isEmpty() const
d->attributeListMap.isEmpty();
}
static const char *keyTranslation[][2] = {
{ "WM/AlbumTitle", "ALBUM" },
{ "WM/Composer", "COMPOSER" },
{ "WM/Writer", "WRITER" },
{ "WM/Conductor", "CONDUCTOR" },
{ "WM/ModifiedBy", "REMIXER" },
{ "WM/Year", "DATE" },
{ "WM/OriginalReleaseYear", "ORIGINALDATE" },
{ "WM/Producer", "PRODUCER" },
{ "WM/ContentGroupDescription", "GROUPING" },
{ "WM/SubTitle", "SUBTITLE" },
{ "WM/SetSubTitle", "DISCSUBTITLE" },
{ "WM/TrackNumber", "TRACKNUMBER" },
{ "WM/PartOfSet", "DISCNUMBER" },
{ "WM/Genre", "GENRE" },
{ "WM/BeatsPerMinute", "BPM" },
{ "WM/Mood", "MOOD" },
{ "WM/ISRC", "ISRC" },
{ "WM/Lyrics", "LYRICS" },
{ "WM/Media", "MEDIA" },
{ "WM/Publisher", "LABEL" },
{ "WM/CatalogNo", "CATALOGNUMBER" },
{ "WM/Barcode", "BARCODE" },
{ "WM/EncodedBy", "ENCODEDBY" },
{ "WM/AlbumSortOrder", "ALBUMSORT" },
{ "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" },
{ "WM/ArtistSortOrder", "ARTISTSORT" },
{ "WM/TitleSortOrder", "TITLESORT" },
{ "WM/Script", "SCRIPT" },
{ "WM/Language", "LANGUAGE" },
{ "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" },
{ "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" },
{ "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" },
{ "MusicIP/PUID", "MUSICIP_PUID" },
{ "Acoustid/Id", "ACOUSTID_ID" },
{ "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" },
};
namespace
{
const char *keyTranslation[][2] = {
{ "WM/AlbumTitle", "ALBUM" },
{ "WM/Composer", "COMPOSER" },
{ "WM/Writer", "WRITER" },
{ "WM/Conductor", "CONDUCTOR" },
{ "WM/ModifiedBy", "REMIXER" },
{ "WM/Year", "DATE" },
{ "WM/OriginalReleaseYear", "ORIGINALDATE" },
{ "WM/Producer", "PRODUCER" },
{ "WM/ContentGroupDescription", "GROUPING" },
{ "WM/SubTitle", "SUBTITLE" },
{ "WM/SetSubTitle", "DISCSUBTITLE" },
{ "WM/TrackNumber", "TRACKNUMBER" },
{ "WM/PartOfSet", "DISCNUMBER" },
{ "WM/Genre", "GENRE" },
{ "WM/BeatsPerMinute", "BPM" },
{ "WM/Mood", "MOOD" },
{ "WM/ISRC", "ISRC" },
{ "WM/Lyrics", "LYRICS" },
{ "WM/Media", "MEDIA" },
{ "WM/Publisher", "LABEL" },
{ "WM/CatalogNo", "CATALOGNUMBER" },
{ "WM/Barcode", "BARCODE" },
{ "WM/EncodedBy", "ENCODEDBY" },
{ "WM/AlbumSortOrder", "ALBUMSORT" },
{ "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" },
{ "WM/ArtistSortOrder", "ARTISTSORT" },
{ "WM/TitleSortOrder", "TITLESORT" },
{ "WM/Script", "SCRIPT" },
{ "WM/Language", "LANGUAGE" },
{ "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" },
{ "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" },
{ "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" },
{ "MusicIP/PUID", "MUSICIP_PUID" },
{ "Acoustid/Id", "ACOUSTID_ID" },
{ "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" },
};
}
PropertyMap ASF::Tag::properties() const
{

View File

@@ -59,24 +59,130 @@
using namespace TagLib;
namespace
{
typedef List<const FileRef::FileTypeResolver *> ResolverList;
typedef ResolverList::ConstIterator ResolverConstIterator;
ResolverList fileTypeResolvers;
RefCountPtr<File> create(
FileName fileName,
bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
RefCountPtr<File> file;
for(ResolverConstIterator it = fileTypeResolvers.begin(); it != fileTypeResolvers.end(); ++it)
{
file.reset((*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle));
if(file)
return file;
}
String ext;
#ifdef _WIN32
// Avoids direct conversion from FileName to String
// because String can't decode strings in local encodings properly.
if(!fileName.wstr().empty()) {
const wchar_t *pext = PathFindExtensionW(fileName.wstr().c_str());
if(*pext == L'.')
ext = String(pext + 1).upper();
}
else {
const char *pext = PathFindExtensionA(fileName.str().c_str());
if(*pext == '.')
ext = String(pext + 1).upper();
}
#else
{
String s = fileName;
const size_t pos = s.rfind(".");
if(pos != String::npos)
ext = s.substr(pos + 1).upper();
}
#endif
// 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")
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));
}
return file;
}
}
class FileRef::FileRefPrivate
{
public:
FileRefPrivate(File *f) : file(f) {}
FileRefPrivate()
: file()
{
}
TAGLIB_SHARED_PTR<File> file;
FileRefPrivate(File *f)
: file(f)
{
}
FileRefPrivate(RefCountPtr<File> f)
: file(f)
{
}
static List<const FileTypeResolver *> fileTypeResolvers;
RefCountPtr<File> file;
};
List<const FileRef::FileTypeResolver *> FileRef::FileRefPrivate::fileTypeResolvers;
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
FileRef::FileRef()
: d(new FileRefPrivate(0))
: d(new FileRefPrivate())
{
}
@@ -118,6 +224,36 @@ Tag *FileRef::tag() const
return d->file->tag();
}
PropertyMap FileRef::properties() const
{
if(isNull()) {
debug("FileRef::properties() - Called without a valid file.");
return PropertyMap();
}
return d->file->properties();
}
void FileRef::removeUnsupportedProperties(const StringList& properties)
{
if(isNull()) {
debug("FileRef::removeUnsupportedProperties() - Called without a valid file.");
return;
}
d->file->removeUnsupportedProperties(properties);
}
PropertyMap FileRef::setProperties(const PropertyMap &properties)
{
if(isNull()) {
debug("FileRef::setProperties() - Called without a valid file.");
return PropertyMap();
}
return d->file->setProperties(properties);
}
AudioProperties *FileRef::audioProperties() const
{
if(isNull()) {
@@ -143,7 +279,7 @@ bool FileRef::save()
const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static
{
FileRefPrivate::fileTypeResolvers.prepend(resolver);
fileTypeResolvers.prepend(resolver);
return resolver;
}
@@ -182,9 +318,14 @@ StringList FileRef::defaultFileExtensions()
return l;
}
bool FileRef::isValid() const
{
return (d->file && d->file->isValid());
}
bool FileRef::isNull() const
{
return !d->file || !d->file->isValid();
return !isValid();
}
FileRef &FileRef::operator=(const FileRef &ref)
@@ -212,93 +353,3 @@ bool FileRef::operator!=(const FileRef &ref) const
{
return ref.d->file != d->file;
}
File *FileRef::create(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle) // static
{
List<const FileTypeResolver *>::ConstIterator it = FileRefPrivate::fileTypeResolvers.begin();
for(; it != FileRefPrivate::fileTypeResolvers.end(); ++it) {
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
if(file)
return file;
}
String ext;
#ifdef _WIN32
// Avoids direct conversion from FileName to String
// because String can't decode strings in local encodings properly.
if(!fileName.wstr().empty()) {
const wchar_t *pext = PathFindExtensionW(fileName.wstr().c_str());
if(*pext == L'.')
ext = String(pext + 1).upper();
}
else {
const char *pext = PathFindExtensionA(fileName.str().c_str());
if(*pext == '.')
ext = String(pext + 1).upper();
}
#else
{
String s = fileName;
const size_t pos = s.rfind(".");
if(pos != String::npos)
ext = s.substr(pos + 1).upper();
}
#endif
// 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")
return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OGG")
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OGA") {
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
if (file->isValid())
return file;
delete file;
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
}
if(ext == "FLAC")
return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "MPC")
return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WV")
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "SPX")
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OPUS")
return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "TTA")
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2")
return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WMA" || ext == "ASF")
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "AIF" || ext == "AIFF")
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WAV")
return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "APE")
return new APE::File(fileName, readAudioProperties, audioPropertiesStyle);
// module, nst and wow are possible but uncommon extensions
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "S3M")
return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "IT")
return new IT::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(fileName, readAudioProperties, audioPropertiesStyle);
}
return 0;
}

View File

@@ -26,10 +26,10 @@
#ifndef TAGLIB_FILEREF_H
#define TAGLIB_FILEREF_H
#include "taglib_export.h"
#include "tfile.h"
#include "tstringlist.h"
#include "taglib_export.h"
#include "tpropertymap.h"
#include "audioproperties.h"
#if _WIN32
@@ -172,6 +172,41 @@ namespace TagLib {
*/
Tag *tag() const;
/*!
* Exports the tags of the file as dictionary mapping (human readable) tag
* names (uppercase Strings) to StringLists of tag values. Calls the according
* specialization in the File subclasses.
* For each metadata object of the file that could not be parsed into the PropertyMap
* format, the returend map's unsupportedData() list will contain one entry identifying
* that object (e.g. the frame type for ID3v2 tags). Use removeUnsupportedProperties()
* to remove (a subset of) them.
* For files that contain more than one tag (e.g. an MP3 with both an ID3v1 and an ID3v2
* tag) only the most "modern" one will be exported (ID3v2 in this case).
*/
PropertyMap properties() const;
/*!
* Removes unsupported properties, or a subset of them, from the file's metadata.
* The parameter \a properties must contain only entries from
* properties().unsupportedData().
*/
void removeUnsupportedProperties(const StringList& properties);
/*!
* Sets the tags of this File to those specified in \a properties. Calls the
* according specialization method in the subclasses of File to do the translation
* into the format-specific details.
* If some value(s) could not be written imported to the specific metadata format,
* the returned PropertyMap will contain those value(s). Otherwise it will be empty,
* indicating that no problems occured.
* With file types that support several tag formats (for instance, MP3 files can have
* ID3v1, ID3v2, and APEv2 tags), this function will create the most appropriate one
* (ID3v2 for MP3 files). Older formats will be updated as well, if they exist, but won't
* be taken into account for the return value of this function.
* See the documentation of the subclass implementations for detailed descriptions.
*/
PropertyMap setProperties(const PropertyMap &properties);
/*!
* Returns the audio properties for this FileRef. If no audio properties
* were read then this will returns a null pointer.
@@ -232,8 +267,17 @@ namespace TagLib {
*/
static StringList defaultFileExtensions();
/*!
* Returns true if the file is open and readable.
*
* \note Just a negative of isNull().
*/
bool isValid() const;
/*!
* Returns true if the file (and as such other pointers) are null.
*
* \note Just a negative of isValid().
*/
bool isNull() const;
@@ -264,25 +308,9 @@ namespace TagLib {
*/
bool operator!=(const FileRef &ref) const;
/*!
* A simple implementation of file type guessing. If \a readAudioProperties
* is true then the audio properties will be read using
* \a audioPropertiesStyle. If \a readAudioProperties is false then
* \a audioPropertiesStyle will be ignored.
*
* \note You generally shouldn't use this method, but instead the constructor
* directly.
*
* \deprecated
*/
static File *create(FileName fileName,
bool readAudioProperties = true,
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
private:
class FileRefPrivate;
TAGLIB_SHARED_PTR<FileRefPrivate> d;
RefCountPtr<FileRefPrivate> d;
};
} // namespace TagLib

View File

@@ -66,7 +66,7 @@ namespace TagLib {
private:
class CoverArtPrivate;
TAGLIB_SHARED_PTR<CoverArtPrivate> d;
RefCountPtr<CoverArtPrivate> d;
};
typedef List<CoverArt> CoverArtList;

View File

@@ -97,7 +97,7 @@ namespace TagLib {
private:
class ItemPrivate;
TAGLIB_SHARED_PTR<ItemPrivate> d;
RefCountPtr<ItemPrivate> d;
};
}

View File

@@ -767,54 +767,57 @@ MP4::Tag::toString() const
return desc.toString("\n");
}
static const char *keyTranslation[][2] = {
{ "\251nam", "TITLE" },
{ "\251ART", "ARTIST" },
{ "\251alb", "ALBUM" },
{ "\251cmt", "COMMENT" },
{ "\251gen", "GENRE" },
{ "\251day", "DATE" },
{ "\251wrt", "COMPOSER" },
{ "\251grp", "GROUPING" },
{ "trkn", "TRACKNUMBER" },
{ "disk", "DISCNUMBER" },
{ "cpil", "COMPILATION" },
{ "tmpo", "BPM" },
{ "cprt", "COPYRIGHT" },
{ "\251lyr", "LYRICS" },
{ "\251too", "ENCODEDBY" },
{ "soal", "ALBUMSORT" },
{ "soaa", "ALBUMARTISTSORT" },
{ "soar", "ARTISTSORT" },
{ "sonm", "TITLESORT" },
{ "soco", "COMPOSERSORT" },
{ "sosn", "SHOWSORT" },
{ "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" },
{ "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
{ "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" },
{ "----:com.apple.iTunes:ASIN", "ASIN" },
{ "----:com.apple.iTunes:LABEL", "LABEL" },
{ "----:com.apple.iTunes:LYRICIST", "LYRICIST" },
{ "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" },
{ "----:com.apple.iTunes:REMIXER", "REMIXER" },
{ "----:com.apple.iTunes:ENGINEER", "ENGINEER" },
{ "----:com.apple.iTunes:PRODUCER", "PRODUCER" },
{ "----:com.apple.iTunes:DJMIXER", "DJMIXER" },
{ "----:com.apple.iTunes:MIXER", "MIXER" },
{ "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" },
{ "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" },
{ "----:com.apple.iTunes:MOOD", "MOOD" },
{ "----:com.apple.iTunes:ISRC", "ISRC" },
{ "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" },
{ "----:com.apple.iTunes:BARCODE", "BARCODE" },
{ "----:com.apple.iTunes:SCRIPT", "SCRIPT" },
{ "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" },
{ "----:com.apple.iTunes:LICENSE", "LICENSE" },
{ "----:com.apple.iTunes:MEDIA", "MEDIA" },
};
namespace
{
const char *keyTranslation[][2] = {
{ "\251nam", "TITLE" },
{ "\251ART", "ARTIST" },
{ "\251alb", "ALBUM" },
{ "\251cmt", "COMMENT" },
{ "\251gen", "GENRE" },
{ "\251day", "DATE" },
{ "\251wrt", "COMPOSER" },
{ "\251grp", "GROUPING" },
{ "trkn", "TRACKNUMBER" },
{ "disk", "DISCNUMBER" },
{ "cpil", "COMPILATION" },
{ "tmpo", "BPM" },
{ "cprt", "COPYRIGHT" },
{ "\251lyr", "LYRICS" },
{ "\251too", "ENCODEDBY" },
{ "soal", "ALBUMSORT" },
{ "soaa", "ALBUMARTISTSORT" },
{ "soar", "ARTISTSORT" },
{ "sonm", "TITLESORT" },
{ "soco", "COMPOSERSORT" },
{ "sosn", "SHOWSORT" },
{ "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" },
{ "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
{ "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" },
{ "----:com.apple.iTunes:ASIN", "ASIN" },
{ "----:com.apple.iTunes:LABEL", "LABEL" },
{ "----:com.apple.iTunes:LYRICIST", "LYRICIST" },
{ "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" },
{ "----:com.apple.iTunes:REMIXER", "REMIXER" },
{ "----:com.apple.iTunes:ENGINEER", "ENGINEER" },
{ "----:com.apple.iTunes:PRODUCER", "PRODUCER" },
{ "----:com.apple.iTunes:DJMIXER", "DJMIXER" },
{ "----:com.apple.iTunes:MIXER", "MIXER" },
{ "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" },
{ "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" },
{ "----:com.apple.iTunes:MOOD", "MOOD" },
{ "----:com.apple.iTunes:ISRC", "ISRC" },
{ "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" },
{ "----:com.apple.iTunes:BARCODE", "BARCODE" },
{ "----:com.apple.iTunes:SCRIPT", "SCRIPT" },
{ "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" },
{ "----:com.apple.iTunes:LICENSE", "LICENSE" },
{ "----:com.apple.iTunes:MEDIA", "MEDIA" },
};
}
PropertyMap MP4::Tag::properties() const
{

View File

@@ -157,36 +157,39 @@ int MPC::AudioProperties::albumPeak() const
// private members
////////////////////////////////////////////////////////////////////////////////
unsigned long readSize(File *file, size_t &sizelength)
namespace
{
unsigned char tmp;
unsigned long size = 0;
unsigned long readSize(File *file, size_t &sizelength)
{
unsigned char tmp;
unsigned long size = 0;
do {
ByteVector b = file->readBlock(1);
tmp = b[0];
size = (size << 7) | (tmp & 0x7F);
sizelength++;
} while((tmp & 0x80));
return size;
do {
ByteVector b = file->readBlock(1);
tmp = b[0];
size = (size << 7) | (tmp & 0x7F);
sizelength++;
} while((tmp & 0x80));
return size;
}
unsigned long readSize(const ByteVector &data, size_t &sizelength)
{
unsigned char tmp;
unsigned long size = 0;
unsigned long pos = 0;
do {
tmp = data[pos++];
size = (size << 7) | (tmp & 0x7F);
sizelength++;
} while((tmp & 0x80) && (pos < data.size()));
return size;
}
static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 };
}
unsigned long readSize(const ByteVector &data, size_t &sizelength)
{
unsigned char tmp;
unsigned long size = 0;
unsigned long pos = 0;
do {
tmp = data[pos++];
size = (size << 7) | (tmp & 0x7F);
sizelength++;
} while((tmp & 0x80) && (pos < data.size()));
return size;
}
static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 };
void MPC::AudioProperties::readSV8(File *file)
{
bool readSH = false, readRG = false;

View File

@@ -51,7 +51,11 @@ public:
static const TagLib::StringHandler *stringHandler;
};
static const ID3v1::StringHandler defaultStringHandler;
namespace
{
const ID3v1::StringHandler defaultStringHandler;
}
const TagLib::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = &defaultStringHandler;
////////////////////////////////////////////////////////////////////////////////

View File

@@ -31,20 +31,23 @@
using namespace TagLib;
using namespace ID3v2;
static inline int bitsToBytes(int i)
namespace
{
return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1;
static inline int bitsToBytes(int i)
{
return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1;
}
struct ChannelData
{
ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {}
RelativeVolumeFrame::ChannelType channelType;
short volumeAdjustment;
RelativeVolumeFrame::PeakVolume peakVolume;
};
}
struct ChannelData
{
ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {}
RelativeVolumeFrame::ChannelType channelType;
short volumeAdjustment;
RelativeVolumeFrame::PeakVolume peakVolume;
};
class RelativeVolumeFrame::RelativeVolumeFramePrivate
{
public:

View File

@@ -119,15 +119,18 @@ void TextIdentificationFrame::setTextEncoding(String::Type encoding)
d->textEncoding = encoding;
}
// array of allowed TIPL prefixes and their corresponding key value
static const TagLib::uint involvedPeopleSize = 5;
static const char* involvedPeople[][2] = {
{"ARRANGER", "ARRANGER"},
{"ENGINEER", "ENGINEER"},
{"PRODUCER", "PRODUCER"},
{"DJ-MIX", "DJMIXER"},
{"MIX", "MIXER"},
};
namespace
{
// array of allowed TIPL prefixes and their corresponding key value
static const TagLib::uint involvedPeopleSize = 5;
static const char* involvedPeople[][2] = {
{"ARRANGER", "ARRANGER"},
{"ENGINEER", "ENGINEER"},
{"PRODUCER", "PRODUCER"},
{"DJ-MIX", "DJMIXER"},
{"MIX", "MIXER"},
};
}
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
{

View File

@@ -319,121 +319,125 @@ String::Type Frame::checkTextEncoding(const StringList &fields, String::Type enc
return checkEncoding(fields, encoding, header()->version());
}
static const TagLib::uint frameTranslationSize = 51;
static const char *frameTranslation[][2] = {
// Text information frames
{ "TALB", "ALBUM"},
{ "TBPM", "BPM" },
{ "TCOM", "COMPOSER" },
{ "TCON", "GENRE" },
{ "TCOP", "COPYRIGHT" },
{ "TDEN", "ENCODINGTIME" },
{ "TDLY", "PLAYLISTDELAY" },
{ "TDOR", "ORIGINALDATE" },
{ "TDRC", "DATE" },
// { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
{ "TDRL", "RELEASEDATE" },
{ "TDTG", "TAGGINGDATE" },
{ "TENC", "ENCODEDBY" },
{ "TEXT", "LYRICIST" },
{ "TFLT", "FILETYPE" },
//{ "TIPL", "INVOLVEDPEOPLE" }, handled separately
{ "TIT1", "CONTENTGROUP" },
{ "TIT2", "TITLE"},
{ "TIT3", "SUBTITLE" },
{ "TKEY", "INITIALKEY" },
{ "TLAN", "LANGUAGE" },
{ "TLEN", "LENGTH" },
//{ "TMCL", "MUSICIANCREDITS" }, handled separately
{ "TMED", "MEDIA" },
{ "TMOO", "MOOD" },
{ "TOAL", "ORIGINALALBUM" },
{ "TOFN", "ORIGINALFILENAME" },
{ "TOLY", "ORIGINALLYRICIST" },
{ "TOPE", "ORIGINALARTIST" },
{ "TOWN", "OWNER" },
{ "TPE1", "ARTIST"},
{ "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST'
{ "TPE3", "CONDUCTOR" },
{ "TPE4", "REMIXER" }, // could also be ARRANGER
{ "TPOS", "DISCNUMBER" },
{ "TPRO", "PRODUCEDNOTICE" },
{ "TPUB", "LABEL" },
{ "TRCK", "TRACKNUMBER" },
{ "TRSN", "RADIOSTATION" },
{ "TRSO", "RADIOSTATIONOWNER" },
{ "TSOA", "ALBUMSORT" },
{ "TSOP", "ARTISTSORT" },
{ "TSOT", "TITLESORT" },
{ "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes
{ "TSRC", "ISRC" },
{ "TSSE", "ENCODING" },
// URL frames
{ "WCOP", "COPYRIGHTURL" },
{ "WOAF", "FILEWEBPAGE" },
{ "WOAR", "ARTISTWEBPAGE" },
{ "WOAS", "AUDIOSOURCEWEBPAGE" },
{ "WORS", "RADIOSTATIONWEBPAGE" },
{ "WPAY", "PAYMENTWEBPAGE" },
{ "WPUB", "PUBLISHERWEBPAGE" },
//{ "WXXX", "URL"}, handled specially
// Other frames
{ "COMM", "COMMENT" },
//{ "USLT", "LYRICS" }, handled specially
};
static const TagLib::uint txxxFrameTranslationSize = 7;
static const char *txxxFrameTranslation[][2] = {
{ "MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
{ "MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "MusicBrainz Work Id", "MUSICBRAINZ_WORKID" },
{ "Acoustid Id", "ACOUSTID_ID" },
{ "Acoustid Fingerprint", "ACOUSTID_FINGERPRINT" },
{ "MusicIP PUID", "MUSICIP_PUID" },
};
Map<ByteVector, String> &idMap()
namespace
{
static Map<ByteVector, String> m;
if(m.isEmpty())
for(size_t i = 0; i < frameTranslationSize; ++i)
m[frameTranslation[i][0]] = frameTranslation[i][1];
return m;
}
static const TagLib::uint frameTranslationSize = 51;
static const char *frameTranslation[][2] = {
// Text information frames
{ "TALB", "ALBUM"},
{ "TBPM", "BPM" },
{ "TCOM", "COMPOSER" },
{ "TCON", "GENRE" },
{ "TCOP", "COPYRIGHT" },
{ "TDEN", "ENCODINGTIME" },
{ "TDLY", "PLAYLISTDELAY" },
{ "TDOR", "ORIGINALDATE" },
{ "TDRC", "DATE" },
// { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
// { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4
{ "TDRL", "RELEASEDATE" },
{ "TDTG", "TAGGINGDATE" },
{ "TENC", "ENCODEDBY" },
{ "TEXT", "LYRICIST" },
{ "TFLT", "FILETYPE" },
//{ "TIPL", "INVOLVEDPEOPLE" }, handled separately
{ "TIT1", "CONTENTGROUP" },
{ "TIT2", "TITLE"},
{ "TIT3", "SUBTITLE" },
{ "TKEY", "INITIALKEY" },
{ "TLAN", "LANGUAGE" },
{ "TLEN", "LENGTH" },
//{ "TMCL", "MUSICIANCREDITS" }, handled separately
{ "TMED", "MEDIA" },
{ "TMOO", "MOOD" },
{ "TOAL", "ORIGINALALBUM" },
{ "TOFN", "ORIGINALFILENAME" },
{ "TOLY", "ORIGINALLYRICIST" },
{ "TOPE", "ORIGINALARTIST" },
{ "TOWN", "OWNER" },
{ "TPE1", "ARTIST"},
{ "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST'
{ "TPE3", "CONDUCTOR" },
{ "TPE4", "REMIXER" }, // could also be ARRANGER
{ "TPOS", "DISCNUMBER" },
{ "TPRO", "PRODUCEDNOTICE" },
{ "TPUB", "LABEL" },
{ "TRCK", "TRACKNUMBER" },
{ "TRSN", "RADIOSTATION" },
{ "TRSO", "RADIOSTATIONOWNER" },
{ "TSOA", "ALBUMSORT" },
{ "TSOP", "ARTISTSORT" },
{ "TSOT", "TITLESORT" },
{ "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes
{ "TSRC", "ISRC" },
{ "TSSE", "ENCODING" },
// URL frames
{ "WCOP", "COPYRIGHTURL" },
{ "WOAF", "FILEWEBPAGE" },
{ "WOAR", "ARTISTWEBPAGE" },
{ "WOAS", "AUDIOSOURCEWEBPAGE" },
{ "WORS", "RADIOSTATIONWEBPAGE" },
{ "WPAY", "PAYMENTWEBPAGE" },
{ "WPUB", "PUBLISHERWEBPAGE" },
//{ "WXXX", "URL"}, handled specially
// Other frames
{ "COMM", "COMMENT" },
//{ "USLT", "LYRICS" }, handled specially
};
Map<String, String> &txxxMap()
{
static Map<String, String> m;
if(m.isEmpty()) {
for(size_t i = 0; i < txxxFrameTranslationSize; ++i) {
String key = String(txxxFrameTranslation[i][0]).upper();
m[key] = txxxFrameTranslation[i][1];
}
static const TagLib::uint txxxFrameTranslationSize = 7;
static const char *txxxFrameTranslation[][2] = {
{ "MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
{ "MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "MusicBrainz Work Id", "MUSICBRAINZ_WORKID" },
{ "Acoustid Id", "ACOUSTID_ID" },
{ "Acoustid Fingerprint", "ACOUSTID_FINGERPRINT" },
{ "MusicIP PUID", "MUSICIP_PUID" },
};
Map<ByteVector, String> &idMap()
{
static Map<ByteVector, String> m;
if(m.isEmpty())
for(size_t i = 0; i < frameTranslationSize; ++i)
m[frameTranslation[i][0]] = frameTranslation[i][1];
return m;
}
return m;
}
// list of deprecated frames and their successors
static const TagLib::uint deprecatedFramesSize = 4;
static const char *deprecatedFrames[][2] = {
{"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3)
{"TDAT", "TDRC"}, // 2.3 -> 2.4
{"TYER", "TDRC"}, // 2.3 -> 2.4
{"TIME", "TDRC"}, // 2.3 -> 2.4
};
Map<String, String> &txxxMap()
{
static Map<String, String> m;
if(m.isEmpty()) {
for(size_t i = 0; i < txxxFrameTranslationSize; ++i) {
String key = String(txxxFrameTranslation[i][0]).upper();
m[key] = txxxFrameTranslation[i][1];
}
}
return m;
}
Map<ByteVector,ByteVector> &deprecationMap()
{
static Map<ByteVector,ByteVector> depMap;
if(depMap.isEmpty())
for(TagLib::uint i = 0; i < deprecatedFramesSize; ++i)
depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1];
return depMap;
// list of deprecated frames and their successors
static const TagLib::uint deprecatedFramesSize = 4;
static const char *deprecatedFrames[][2] = {
{"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3)
{"TDAT", "TDRC"}, // 2.3 -> 2.4
{"TYER", "TDRC"}, // 2.3 -> 2.4
{"TIME", "TDRC"}, // 2.3 -> 2.4
};
Map<ByteVector,ByteVector> &deprecationMap()
{
static Map<ByteVector,ByteVector> depMap;
if(depMap.isEmpty())
for(TagLib::uint i = 0; i < deprecatedFramesSize; ++i)
depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1];
return depMap;
}
}
String Frame::frameIDToKey(const ByteVector &id)

View File

@@ -74,7 +74,11 @@ public:
static const TagLib::StringHandler *stringHandler;
};
static const ID3v2::Latin1StringHandler defaultStringHandler;
namespace
{
const ID3v2::Latin1StringHandler defaultStringHandler;
}
const TagLib::StringHandler *ID3v2::Tag::TagPrivate::stringHandler = &defaultStringHandler;
////////////////////////////////////////////////////////////////////////////////

View File

@@ -181,7 +181,7 @@ namespace TagLib {
void parse(const ByteVector &data);
class HeaderPrivate;
TAGLIB_SHARED_PTR<HeaderPrivate> d;
RefCountPtr<HeaderPrivate> d;
};
}
}

View File

@@ -73,7 +73,7 @@ namespace TagLib {
void read(const ByteVector &data);
class PropertiesPrivate;
TAGLIB_SHARED_PTR<PropertiesPrivate> d;
RefCountPtr<PropertiesPrivate> d;
};
}
}

View File

@@ -32,13 +32,16 @@
using namespace TagLib;
struct Chunk
namespace
{
ByteVector name;
offset_t offset;
TagLib::uint size;
char padding;
};
struct Chunk
{
ByteVector name;
offset_t offset;
TagLib::uint size;
char padding;
};
}
class RIFF::File::FilePrivate
{
@@ -250,17 +253,20 @@ void RIFF::File::removeChunk(const ByteVector &name)
// private members
////////////////////////////////////////////////////////////////////////////////
static bool isValidChunkID(const ByteVector &name)
namespace
{
if(name.size() != 4) {
return false;
}
for(int i = 0; i < 4; i++) {
if(name[i] < 32 || name[i] > 127) {
bool isValidChunkID(const ByteVector &name)
{
if(name.size() != 4) {
return false;
}
for(int i = 0; i < 4; i++) {
if(name[i] < 32 || name[i] > 127) {
return false;
}
}
return true;
}
return true;
}
void RIFF::File::read()

View File

@@ -57,7 +57,11 @@ public:
static const TagLib::StringHandler *stringHandler;
};
static const RIFF::Info::StringHandler defaultStringHandler;
namespace
{
const RIFF::Info::StringHandler defaultStringHandler;
}
const TagLib::StringHandler *RIFF::Info::Tag::TagPrivate::stringHandler = &defaultStringHandler;
////////////////////////////////////////////////////////////////////////////////

View File

@@ -7,7 +7,11 @@
#cmakedefine TAGLIB_USE_MOVE_SEMANTICS 1
/* Defined if your compiler supports shared_ptr */
#cmakedefine TAGLIB_USE_STD_SHARED_PTR 1
#cmakedefine TAGLIB_USE_TR1_SHARED_PTR 1
#cmakedefine TAGLIB_USE_BOOST_SHARED_PTR 1
#cmakedefine TAGLIB_USE_STD_SHARED_PTR 1 // #include <memory> / std::shared_ptr<T>
#cmakedefine TAGLIB_USE_TR1_SHARED_PTR 1 // #include <tr1/memory> / std::tr1::shared_ptr<T>
#cmakedefine TAGLIB_USE_BOOST_SHARED_PTR 1 // #include <boost/shared_ptr.hpp> / boost::shared_ptr<T>
/* Defined if your compiler supports unique_ptr or scoped_ptr */
#cmakedefine TAGLIB_USE_STD_UNIQUE_PTR 1 // #include <memory> / std::unique_ptr<T>
#cmakedefine TAGLIB_USE_BOOST_SCOPED_PTR 1 // #include <boost/scoped_ptr.hpp> / boost::scoped_ptr<T>

View File

@@ -31,7 +31,7 @@ using namespace TagLib;
namespace
{
typedef std::vector<TAGLIB_SHARED_PTR<Tag> > TagVector;
typedef std::vector<RefCountPtr<Tag> > TagVector;
typedef TagVector::iterator TagIterator;
typedef TagVector::const_iterator TagConstIterator;
}
@@ -66,7 +66,7 @@ public:
{
}
std::vector<TAGLIB_SHARED_PTR<Tag> > tags;
TagVector tags;
};
TagUnion::TagUnion(size_t count)

View File

@@ -89,7 +89,7 @@ namespace TagLib {
TagUnion &operator=(const Tag &);
class TagUnionPrivate;
TAGLIB_SHARED_PTR<TagUnionPrivate> d;
NonRefCountPtr<TagUnionPrivate> d;
};
}

View File

@@ -301,7 +301,7 @@ namespace {
LittleEndian,
BigEndian
};
}
}
template <typename T, size_t LENGTH, Endianness ENDIAN>
inline T toNumber(const ByteVector &v, size_t offset)
@@ -312,12 +312,7 @@ inline T toNumber(const ByteVector &v, size_t offset)
static const bool swap = (ENDIAN == LittleEndian);
#endif
if(offset + LENGTH > v.size()) {
debug("toNumber<T>() -- offset is out of range. Returning 0.");
return 0;
}
if(LENGTH >= sizeof(T)) {
if(LENGTH >= sizeof(T) && offset + LENGTH <= v.size()) {
// Uses memcpy instead of reinterpret_cast to avoid an alignment exception.
T tmp;
::memcpy(&tmp, v.data() + offset, sizeof(T));
@@ -328,9 +323,10 @@ inline T toNumber(const ByteVector &v, size_t offset)
return tmp;
}
else {
const size_t length = std::min(LENGTH, v.size() - offset);
T sum = 0;
for(size_t i = 0; i < LENGTH; i++) {
const size_t shift = (ENDIAN == LittleEndian ? i : LENGTH - 1 - i) * 8;
for(size_t i = 0; i < length; i++) {
const size_t shift = (ENDIAN == LittleEndian ? i : length - 1 - i) * 8;
sum |= static_cast<T>(static_cast<uchar>(v[offset + i])) << shift;
}
@@ -363,7 +359,7 @@ public:
{
}
ByteVectorPrivate(TAGLIB_SHARED_PTR<ByteVectorPrivate> d, size_t o, size_t l)
ByteVectorPrivate(RefCountPtr<ByteVectorPrivate> d, size_t o, size_t l)
: data(d->data)
, offset(d->offset + o)
, length(l)
@@ -411,7 +407,7 @@ public:
return *this;
}
TAGLIB_SHARED_PTR<std::vector<char> > data;
RefCountPtr<std::vector<char> > data;
size_t offset;
size_t length;
};
@@ -717,9 +713,11 @@ size_t ByteVector::size() const
ByteVector &ByteVector::resize(size_t size, char padding)
{
detach();
d->data->resize(d->offset + size, padding);
d->length = size;
if(size != d->length) {
detach();
d->data->resize(d->offset + size, padding);
d->length = size;
}
return *this;
}

View File

@@ -551,7 +551,7 @@ namespace TagLib {
private:
class ByteVectorPrivate;
TAGLIB_SHARED_PTR<ByteVectorPrivate> d;
RefCountPtr<ByteVectorPrivate> d;
};
/*!

View File

@@ -27,11 +27,6 @@
using namespace TagLib;
class ByteVectorListPrivate
{
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////

View File

@@ -28,103 +28,76 @@
#include "tstring.h"
#include "tdebug.h"
#include "tpropertymap.h"
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#ifdef _WIN32
# include <wchar.h>
# include <windows.h>
# include <io.h>
# define ftruncate _chsize
#else
# include <unistd.h>
#endif
#include <stdlib.h>
#ifndef R_OK
# define R_OK 4
#endif
#ifndef W_OK
# define W_OK 2
#endif
#include "asffile.h"
#include "mpegfile.h"
#include "vorbisfile.h"
#include "flacfile.h"
#include "oggflacfile.h"
#include "mpcfile.h"
#include "mp4file.h"
#include "wavpackfile.h"
#include "speexfile.h"
#include "opusfile.h"
#include "trueaudiofile.h"
#include "aifffile.h"
#include "wavfile.h"
#include "apefile.h"
#include "modfile.h"
#include "s3mfile.h"
#include "itfile.h"
#include "xmfile.h"
#include "mp4file.h"
#include "audioproperties.h"
using namespace TagLib;
class File::FilePrivate
class File::FilePrivateBase
{
public:
FilePrivate(IOStream *stream, bool owner);
FilePrivateBase()
: valid(true)
{
}
virtual ~FilePrivateBase()
{
}
virtual IOStream *stream() const = 0;
IOStream *stream;
bool streamOwner;
bool valid;
#ifdef _WIN32
static const size_t bufferSize = 8192;
#else
static const size_t bufferSize = 1024;
#endif
};
File::FilePrivate::FilePrivate(IOStream *stream, bool owner) :
stream(stream),
streamOwner(owner),
valid(true)
// FilePrivate implementation which takes ownership of the stream.
class File::ManagedFilePrivate : public File::FilePrivateBase
{
}
public:
ManagedFilePrivate(IOStream *stream)
: p(stream)
{
}
virtual IOStream *stream() const
{
return p.get();
}
private:
NonRefCountPtr<IOStream> p;
};
// FilePrivate implementation which doesn't take ownership of the stream.
class File::UnmanagedFilePrivate : public File::FilePrivateBase
{
public:
UnmanagedFilePrivate(IOStream *stream)
: p(stream)
{
}
virtual IOStream *stream() const
{
return p;
}
private:
IOStream *p;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
File::File(FileName fileName)
{
IOStream *stream = new FileStream(fileName);
d = new FilePrivate(stream, true);
}
File::File(IOStream *stream)
{
d = new FilePrivate(stream, false);
}
File::~File()
{
if(d->stream && d->streamOwner)
delete d->stream;
delete d;
}
FileName File::name() const
{
return d->stream->name();
return d->stream()->name();
}
PropertyMap File::properties() const
@@ -144,17 +117,17 @@ PropertyMap File::setProperties(const PropertyMap &properties)
ByteVector File::readBlock(size_t length)
{
return d->stream->readBlock(length);
return d->stream()->readBlock(length);
}
void File::writeBlock(const ByteVector &data)
{
d->stream->writeBlock(data);
d->stream()->writeBlock(data);
}
offset_t File::find(const ByteVector &pattern, offset_t fromOffset, const ByteVector &before)
{
if(!d->stream || pattern.size() > d->bufferSize)
if(!d->stream() || pattern.size() > bufferSize())
return -1;
// The position in the file that the current buffer starts at.
@@ -203,20 +176,20 @@ offset_t File::find(const ByteVector &pattern, offset_t fromOffset, const ByteVe
// (1) previous partial match
if(previousPartialMatch != ByteVector::npos
&& d->bufferSize > previousPartialMatch)
&& bufferSize() > previousPartialMatch)
{
const size_t patternOffset = (d->bufferSize - previousPartialMatch);
const size_t patternOffset = (bufferSize() - previousPartialMatch);
if(buffer.containsAt(pattern, 0, patternOffset)) {
seek(originalPosition);
return bufferOffset - d->bufferSize + previousPartialMatch;
return bufferOffset - bufferSize() + previousPartialMatch;
}
}
if(!before.isNull()
&& beforePreviousPartialMatch != ByteVector::npos
&& d->bufferSize > beforePreviousPartialMatch)
&& bufferSize() > beforePreviousPartialMatch)
{
const size_t beforeOffset = (d->bufferSize - beforePreviousPartialMatch);
const size_t beforeOffset = (bufferSize() - beforePreviousPartialMatch);
if(buffer.containsAt(before, 0, beforeOffset)) {
seek(originalPosition);
return -1;
@@ -243,7 +216,7 @@ offset_t File::find(const ByteVector &pattern, offset_t fromOffset, const ByteVe
if(!before.isNull())
beforePreviousPartialMatch = buffer.endsWithPartialMatch(before);
bufferOffset += d->bufferSize;
bufferOffset += bufferSize();
}
// Since we hit the end of the file, reset the status before continuing.
@@ -258,21 +231,9 @@ offset_t File::find(const ByteVector &pattern, offset_t fromOffset, const ByteVe
offset_t File::rfind(const ByteVector &pattern, offset_t fromOffset, const ByteVector &before)
{
if(!d->stream || pattern.size() > d->bufferSize)
if(!d->stream() || pattern.size() > bufferSize())
return -1;
// The position in the file that the current buffer starts at.
ByteVector buffer;
// These variables are used to keep track of a partial match that happens at
// the end of a buffer.
/*
int previousPartialMatch = -1;
int beforePreviousPartialMatch = -1;
*/
// Save the location of the current read pointer. We will restore the
// position using seek() before all returns.
@@ -282,17 +243,21 @@ offset_t File::rfind(const ByteVector &pattern, offset_t fromOffset, const ByteV
offset_t bufferOffset;
if(fromOffset == 0) {
seek(-1 * int(d->bufferSize), End);
seek(-1 * int(bufferSize()), End);
bufferOffset = tell();
}
else {
seek(fromOffset + -1 * int(d->bufferSize), Beginning);
seek(fromOffset + -1 * int(bufferSize()), Beginning);
bufferOffset = tell();
}
// See the notes in find() for an explanation of this algorithm.
for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) {
while(true)
{
ByteVector buffer = readBlock(bufferSize());
if(buffer.isEmpty())
break;
// TODO: (1) previous partial match
@@ -311,7 +276,7 @@ offset_t File::rfind(const ByteVector &pattern, offset_t fromOffset, const ByteV
// TODO: (3) partial match
bufferOffset -= d->bufferSize;
bufferOffset -= bufferSize();
seek(bufferOffset);
}
@@ -326,22 +291,22 @@ offset_t File::rfind(const ByteVector &pattern, offset_t fromOffset, const ByteV
void File::insert(const ByteVector &data, offset_t start, size_t replace)
{
d->stream->insert(data, start, replace);
d->stream()->insert(data, start, replace);
}
void File::removeBlock(offset_t start, size_t length)
{
d->stream->removeBlock(start, length);
d->stream()->removeBlock(start, length);
}
bool File::readOnly() const
{
return d->stream->readOnly();
return d->stream()->readOnly();
}
bool File::isOpen() const
{
return d->stream->isOpen();
return d->stream()->isOpen();
}
bool File::isValid() const
@@ -351,57 +316,27 @@ bool File::isValid() const
void File::seek(offset_t offset, Position p)
{
d->stream->seek(offset, IOStream::Position(p));
d->stream()->seek(offset, IOStream::Position(p));
}
void File::truncate(offset_t length)
{
d->stream->truncate(length);
d->stream()->truncate(length);
}
void File::clear()
{
d->stream->clear();
d->stream()->clear();
}
offset_t File::tell() const
{
return d->stream->tell();
return d->stream()->tell();
}
offset_t File::length()
{
return d->stream->length();
}
bool File::isReadable(const char *file)
{
#if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later
return _access_s(file, R_OK) == 0;
#else
return access(file, R_OK) == 0;
#endif
}
bool File::isWritable(const char *file)
{
#if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later
return _access_s(file, W_OK) == 0;
#else
return access(file, W_OK) == 0;
#endif
return d->stream()->length();
}
String File::toString() const
@@ -422,9 +357,19 @@ String File::toString() const
// protected members
////////////////////////////////////////////////////////////////////////////////
File::File(const FileName &fileName)
: d(new ManagedFilePrivate(new FileStream(fileName)))
{
}
File::File(IOStream *stream)
: d(new UnmanagedFilePrivate(stream))
{
}
size_t File::bufferSize()
{
return FilePrivate::bufferSize;
return FileStream::bufferSize();
}
void File::setValid(bool valid)

View File

@@ -208,7 +208,7 @@ namespace TagLib {
bool isOpen() const;
/*!
* Returns true if the file is open and readble.
* Returns true if the file is open and readable.
*/
bool isValid() const;
@@ -235,21 +235,6 @@ namespace TagLib {
*/
offset_t length();
/*!
* Returns true if \a file can be opened for reading. If the file does not
* exist, this will return false.
*
* \deprecated
*/
static bool isReadable(const char *file);
/*!
* Returns true if \a file can be opened for writing.
*
* \deprecated
*/
static bool isWritable(const char *name);
/*!
* Returns description of the audio file and its tags.
*/
@@ -257,13 +242,12 @@ namespace TagLib {
protected:
/*!
* Construct a File object and opens the \a file. \a file should be a
* be a C-string in the local file system encoding.
* Construct a File object and opens the file specified by \a fileName.
*
* \note Constructor is protected since this class should only be
* instantiated through subclasses.
*/
File(FileName file);
File(const FileName &fileName);
/*!
* Construct a File object and use the \a stream instance.
@@ -297,8 +281,10 @@ namespace TagLib {
File(const File &);
File &operator=(const File &);
class FilePrivate;
FilePrivate *d;
class FilePrivateBase;
class ManagedFilePrivate;
class UnmanagedFilePrivate;
NonRefCountPtr<FilePrivateBase> d;
};
}

View File

@@ -27,17 +27,13 @@
#include "tstring.h"
#include "tdebug.h"
#include <string.h>
#include <sys/stat.h>
#ifndef _WIN32
#ifdef _WIN32
# include <windows.h>
#else
# include <stdio.h>
# include <unistd.h>
#endif
#include <stdlib.h>
#include <limits>
using namespace TagLib;
namespace
@@ -47,10 +43,12 @@ namespace
// Using Win32 native API instead of standard C file I/O to reduce the resource consumption.
typedef FileName FileNameHandle;
typedef HANDLE FileHandle;
# define INVALID_FILE INVALID_HANDLE_VALUE
const size_t BufferSize = 8192;
const FileHandle InvalidFileHandle = INVALID_HANDLE_VALUE;
HANDLE openFile(const FileName &path, bool readOnly)
inline FileHandle openFile(const FileName &path, bool readOnly)
{
const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE);
@@ -59,34 +57,38 @@ namespace
else if(!path.str().empty())
return CreateFileA(path.str().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
else
return INVALID_FILE;
return InvalidFileHandle;
}
size_t fread(void *ptr, size_t size, size_t nmemb, HANDLE stream)
inline void closeFile(FileHandle file)
{
DWORD readLen;
if(ReadFile(stream, ptr, static_cast<DWORD>(size * nmemb), &readLen, NULL))
return (readLen / size);
CloseHandle(file);
}
inline size_t readFile(FileHandle file, ByteVector &buffer)
{
DWORD length;
if(ReadFile(file, buffer.data(), static_cast<DWORD>(buffer.size()), &length, NULL))
return static_cast<size_t>(length);
else
return 0;
}
size_t fwrite(const void *ptr, size_t size, size_t nmemb, HANDLE stream)
inline size_t writeFile(FileHandle file, const ByteVector &buffer)
{
DWORD writtenLen;
if(WriteFile(stream, ptr, static_cast<DWORD>(size * nmemb), &writtenLen, NULL))
return (writtenLen / size);
DWORD length;
if(WriteFile(file, buffer.data(), static_cast<DWORD>(buffer.size()), &length, NULL))
return static_cast<size_t>(length);
else
return 0;
}
# if _DEBUG
# ifndef NDEBUG
// Convert a string in a local encoding into a UTF-16 string.
// This function should only be used to generate an error message.
// In actual use, file names in local encodings are passed to CreateFileA()
// without any conversions.
// Debugging use only. In actual use, file names in local encodings are passed to
// CreateFileA() without any conversions.
String fileNameToString(const FileName &name)
{
@@ -110,9 +112,7 @@ namespace
# endif
#else
# define INVALID_FILE 0
#else // _WIN32
struct FileNameHandle : public std::string
{
@@ -120,99 +120,82 @@ namespace
operator FileName () const { return c_str(); }
};
FILE *openFile(const FileName &path, bool readOnly)
typedef FILE* FileHandle;
const size_t BufferSize = 1024;
const FileHandle InvalidFileHandle = 0;
inline FileHandle openFile(const FileName &path, bool readOnly)
{
return fopen(path, readOnly ? "rb" : "rb+");
}
#endif
inline void closeFile(FileHandle file)
{
fclose(file);
}
inline size_t readFile(FileHandle file, ByteVector &buffer)
{
return fread(buffer.data(), sizeof(char), buffer.size(), file);
}
inline size_t writeFile(FileHandle file, const ByteVector &buffer)
{
return fwrite(buffer.data(), sizeof(char), buffer.size(), file);
}
#endif // _WIN32
}
class FileStream::FileStreamPrivate
{
public:
FileStreamPrivate(const FileName &fileName, bool openReadOnly);
#ifdef _WIN32
HANDLE file;
#else
FILE *file;
#endif
FileStreamPrivate(const FileName &fileName)
: file(InvalidFileHandle)
, name(fileName)
, readOnly(true)
, size(0)
{
}
FileHandle file;
FileNameHandle name;
bool readOnly;
offset_t size;
#ifdef _WIN32
static const size_t bufferSize = 8196;
#else
static const size_t bufferSize = 1024;
#endif
};
FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool openReadOnly) :
file(INVALID_FILE),
name(fileName),
readOnly(true),
size(0)
{
// First try with read / write mode, if that fails, fall back to read only.
if(!openReadOnly)
file = openFile(name, false);
if(file != INVALID_FILE)
readOnly = false;
else
file = openFile(name, true);
if(file == INVALID_FILE)
{
# ifdef _WIN32
debug("Could not open file " + fileNameToString(name));
# else
debug("Could not open file " + String((const char *) name));
# endif
}
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
FileStream::FileStream(FileName file, bool openReadOnly)
: d(new FileStreamPrivate(file, openReadOnly))
FileStream::FileStream(FileName fileName, bool openReadOnly)
: d(new FileStreamPrivate(fileName))
{
// First try with read / write mode, if that fails, fall back to read only.
if(!openReadOnly)
d->file = openFile(fileName, false);
if(d->file != InvalidFileHandle)
d->readOnly = false;
else
d->file = openFile(fileName, true);
if(d->file == InvalidFileHandle)
{
# ifdef _WIN32
debug("Could not open file " + fileNameToString(fileName));
# else
debug("Could not open file " + String(static_cast<const char *>(d->name)));
# endif
}
}
FileStream::~FileStream()
{
#ifdef _WIN32
if(isOpen())
CloseHandle(d->file);
#else
if(isOpen())
fclose(d->file);
#endif
delete d;
closeFile(d->file);
}
FileName FileStream::name() const
@@ -230,13 +213,16 @@ ByteVector FileStream::readBlock(size_t length)
if(length == 0)
return ByteVector::null;
if(length > FileStreamPrivate::bufferSize && static_cast<offset_t>(length) > FileStream::length())
length = static_cast<size_t>(FileStream::length());
const offset_t streamLength = FileStream::length();
if(length > BufferSize && static_cast<offset_t>(length) > streamLength)
length = static_cast<size_t>(streamLength);
ByteVector v(length, 0);
const size_t count = fread(v.data(), sizeof(char), length, d->file);
v.resize(count);
return v;
ByteVector buffer(length);
const size_t count = readFile(d->file, buffer);
buffer.resize(count);
return buffer;
}
void FileStream::writeBlock(const ByteVector &data)
@@ -251,7 +237,7 @@ void FileStream::writeBlock(const ByteVector &data)
return;
}
fwrite(data.data(), sizeof(char), data.size(), d->file);
writeFile(d->file, data);
}
void FileStream::insert(const ByteVector &data, offset_t start, size_t replace)
@@ -272,10 +258,10 @@ void FileStream::insert(const ByteVector &data, offset_t start, size_t replace)
return;
}
else if(data.size() < replace) {
seek(start);
writeBlock(data);
removeBlock(start + data.size(), replace - data.size());
return;
seek(start);
writeBlock(data);
removeBlock(start + data.size(), replace - data.size());
return;
}
// Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore
@@ -288,50 +274,27 @@ void FileStream::insert(const ByteVector &data, offset_t start, size_t replace)
// the *differnce* in the tag sizes. We want to avoid overwriting parts
// that aren't yet in memory, so this is necessary.
size_t bufferLength = FileStreamPrivate::bufferSize;
size_t bufferLength = BufferSize;
while(data.size() - replace > bufferLength)
bufferLength += FileStreamPrivate::bufferSize;
bufferLength += BufferSize;
// Set where to start the reading and writing.
offset_t readPosition = start + replace;
offset_t writePosition = start;
ByteVector buffer;
ByteVector aboutToOverwrite(bufferLength, 0);
// This is basically a special case of the loop below. Here we're just
// doing the same steps as below, but since we aren't using the same buffer
// size -- instead we're using the tag size -- this has to be handled as a
// special case. We're also using File::writeBlock() just for the tag.
// That's a bit slower than using char *'s so, we're only doing it here.
seek(readPosition);
size_t bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
readPosition += bufferLength;
seek(writePosition);
writeBlock(data);
writePosition += data.size();
buffer = aboutToOverwrite;
// In case we've already reached the end of file...
buffer.resize(bytesRead);
// Ok, here's the main loop. We want to loop until the read fails, which
// means that we hit the end of the file.
while(!buffer.isEmpty()) {
ByteVector buffer = data;
ByteVector aboutToOverwrite(bufferLength);
while(true)
{
// Seek to the current read position and read the data that we're about
// to overwrite. Appropriately increment the readPosition.
seek(readPosition);
bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
aboutToOverwrite.resize(static_cast<TagLib::uint>(bytesRead));
const size_t bytesRead = readFile(d->file, aboutToOverwrite);
aboutToOverwrite.resize(bytesRead);
readPosition += bufferLength;
// Check to see if we just read the last block. We need to call clear()
@@ -344,18 +307,18 @@ void FileStream::insert(const ByteVector &data, offset_t start, size_t replace)
// writePosition.
seek(writePosition);
fwrite(buffer.data(), sizeof(char), buffer.size(), d->file);
writeBlock(buffer);
// We hit the end of the file.
if(bytesRead == 0)
break;
writePosition += buffer.size();
// Make the current buffer the data that we read in the beginning.
buffer = aboutToOverwrite;
// Again, we need this for the last write. We don't want to write garbage
// at the end of our file, so we need to set the buffer size to the amount
// that we actually read.
bufferLength = bytesRead;
}
// Clear the file size cache.
@@ -369,18 +332,16 @@ void FileStream::removeBlock(offset_t start, size_t length)
return;
}
size_t bufferLength = FileStreamPrivate::bufferSize;
size_t bufferLength = BufferSize;
offset_t readPosition = start + length;
offset_t writePosition = start;
ByteVector buffer(bufferLength, 0);
size_t bytesRead = 1;
while(bytesRead != 0) {
while(true) {
seek(readPosition);
bytesRead = fread(buffer.data(), sizeof(char), bufferLength, d->file);
const size_t bytesRead = readFile(d->file, buffer);
readPosition += bytesRead;
// Check to see if we just read the last block. We need to call clear()
@@ -390,9 +351,14 @@ void FileStream::removeBlock(offset_t start, size_t length)
clear();
seek(writePosition);
fwrite(buffer.data(), sizeof(char), bytesRead, d->file);
writeFile(d->file, buffer);
if(bytesRead == 0)
break;
writePosition += bytesRead;
}
truncate(writePosition);
}
@@ -403,7 +369,7 @@ bool FileStream::readOnly() const
bool FileStream::isOpen() const
{
return (d->file != INVALID_FILE);
return (d->file != InvalidFileHandle);
}
void FileStream::seek(offset_t offset, Position p)
@@ -558,6 +524,11 @@ offset_t FileStream::length()
#endif
}
size_t FileStream::bufferSize()
{
return BufferSize;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

View File

@@ -135,9 +135,14 @@ namespace TagLib {
*/
void truncate(offset_t length);
/*!
* Returns the buffer size that is used for internal buffering.
*/
static size_t bufferSize();
private:
class FileStreamPrivate;
FileStreamPrivate *d;
NonRefCountPtr<FileStreamPrivate> d;
};
}

View File

@@ -29,39 +29,41 @@ using namespace TagLib;
#ifdef _WIN32
// MSVC 2008 or later can't produce the binary for Win9x.
#if !defined(_MSC_VER) || (_MSC_VER < 1500)
# include "tstring.h"
# include "tdebug.h"
# include <windows.h>
namespace
{
// Check if the running system has CreateFileW() function.
// Windows9x systems don't have CreateFileW() or can't accept Unicode file names.
// Determines whether or not the running system is WinNT.
// In other words, whether the system supports Unicode.
bool isWinNT()
bool supportsUnicode()
{
OSVERSIONINFOA ver = {};
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
if(GetVersionExA(&ver)) {
return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT);
}
else {
return false;
}
const FARPROC p = GetProcAddress(GetModuleHandleA("kernel32"), "CreateFileW");
return (p != NULL);
}
// Indicates whether the system supports Unicode file names.
const bool IsWinNT = isWinNT();
const bool SystemSupportsUnicode = supportsUnicode();
// Converts a UTF-16 string into a local encoding.
// This function should only be used in Windows9x systems which don't support
// Unicode file names.
std::string unicodeToAnsi(const std::wstring &wstr)
std::string unicodeToAnsi(const wchar_t *wstr)
{
const int len = WideCharToMultiByte(CP_ACP, 0, &wstr[0], -1, NULL, 0, NULL, NULL);
if(SystemSupportsUnicode) {
debug("unicodeToAnsi() - Should not be used on WinNT systems.");
}
const int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
if(len == 0)
return std::string();
std::string str(len, '\0');
WideCharToMultiByte(CP_ACP, 0, &wstr[0], -1, &str[0], len, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, wstr, -1, &str[0], len, NULL, NULL);
return str;
}
@@ -71,20 +73,11 @@ namespace
// If Win9x, converts and stores it into m_name to avoid calling Unicode version functions.
FileName::FileName(const wchar_t *name)
: m_wname(IsWinNT ? name : L"")
, m_name(IsWinNT ? "" : unicodeToAnsi(name))
: m_wname(SystemSupportsUnicode ? name : L"")
, m_name (SystemSupportsUnicode ? "" : unicodeToAnsi(name))
{
}
#else
FileName::FileName(const wchar_t *name)
: m_wname(name)
{
}
#endif
FileName::FileName(const char *name)
: m_name(name)
{
@@ -92,7 +85,7 @@ FileName::FileName(const char *name)
FileName::FileName(const FileName &name)
: m_wname(name.m_wname)
, m_name(name.m_name)
, m_name (name.m_name)
{
}
@@ -106,7 +99,7 @@ const std::string &FileName::str() const
return m_name;
}
#endif
#endif // _WIN32
////////////////////////////////////////////////////////////////////////////////
// public members

View File

@@ -305,7 +305,7 @@ namespace TagLib {
private:
#ifndef DO_NOT_DOCUMENT
template <class TP> class ListPrivate;
TAGLIB_SHARED_PTR<ListPrivate<T> > d;
RefCountPtr<ListPrivate<T> > d;
#endif
};

View File

@@ -219,7 +219,7 @@ namespace TagLib {
private:
#ifndef DO_NOT_DOCUMENT
template <class KeyP, class TP> class MapPrivate;
TAGLIB_SHARED_PTR<MapPrivate<Key, T> > d;
RefCountPtr<MapPrivate<Key, T> > d;
#endif
};

View File

@@ -1,273 +0,0 @@
/***************************************************************************
copyright : (C) 2013 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_REFCOUNTPTR_H
#define TAGLIB_REFCOUNTPTR_H
#include <algorithm>
#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class.
/*!
* \internal
* This is just used as a smart pointer for shared classes in TagLib.
*
* \warning This <b>is not</b> part of the TagLib public API!
*/
namespace TagLib {
#if defined(TAGLIB_USE_STD_SHARED_PTR) || defined(TAGLIB_USE_TR1_SHARED_PTR)
#define TAGLIB_SHARED_PTR std::tr1::shared_ptr
#elif defined(TAGLIB_USE_BOOST_SHARED_PTR)
#define TAGLIB_SHARED_PTR boost::shared_ptr
#else // TAGLIB_USE_*_SHARED_PTR
// Self-implements RefCountPtr<T> if shared_ptr<T> is not available.
// I STRONGLY RECOMMEND using standard shared_ptr<T> rather than this class.
class RefCounter
{
public:
RefCounter();
~RefCounter();
size_t ref();
size_t deref();
size_t count() const;
private:
class RefCounterPrivate;
RefCounterPrivate *d;
};
template<typename T>
class RefCountPtr
{
private:
// Counter base class. Provides a reference counter.
class CounterBase
{
public:
virtual ~CounterBase()
{
}
void addref()
{
count.ref();
}
void release()
{
if(count.deref() == 0) {
dispose();
delete this;
}
}
long use_count() const
{
return static_cast<long>(count.count());
}
virtual void dispose() = 0;
private:
RefCounter count;
};
// Counter impl class. Provides a dynamic deleter.
template <typename U>
class CounterImpl : public CounterBase
{
public:
CounterImpl(U *p)
: p(p)
{
}
virtual void dispose()
{
delete p;
}
U *get() const
{
return p;
}
private:
U *p;
};
public:
explicit RefCountPtr()
: counter(0)
{
}
template <typename U>
explicit RefCountPtr(U *p)
: counter(new CounterImpl<U>(p))
{
}
RefCountPtr(const RefCountPtr<T> &x)
: counter(x.counter)
{
if(counter)
counter->addref();
}
template <typename U>
RefCountPtr(const RefCountPtr<U> &x)
: counter(reinterpret_cast<CounterBase*>(x.counter))
{
if(counter)
counter->addref();
}
~RefCountPtr()
{
if(counter)
counter->release();
}
T *get() const
{
if(counter)
return static_cast<CounterImpl<T>*>(counter)->get();
else
return 0;
}
long use_count() const
{
if(counter)
return counter->use_count();
else
return 0;
}
bool unique() const
{
return (use_count() == 1);
}
template <typename U>
void reset(U *p)
{
if(get() != p)
RefCountPtr<T>(p).swap(*this);
}
void reset()
{
RefCountPtr<T>().swap(*this);
}
void swap(RefCountPtr<T> &x)
{
std::swap(counter, x.counter);
}
RefCountPtr<T> &operator=(const RefCountPtr<T> &x)
{
if(get() != x.get()) {
if(counter)
counter->release();
counter = x.counter;
if(counter)
counter->addref();
}
return *this;
}
template <typename U>
RefCountPtr<T> &operator=(const RefCountPtr<U> &x)
{
if(get() != x.get()) {
if(counter)
counter->release();
counter = reinterpret_cast<CounterBase*>(x.counter);
if(counter)
counter->addref();
}
return *this;
}
T& operator*() const
{
return *get();
}
T* operator->() const
{
return get();
}
bool operator==(const RefCountPtr<T> &x) const
{
return (get() == x.get());
}
bool operator!=(const RefCountPtr<T> &x) const
{
return !operator==(x);
}
operator bool() const
{
return (get() != 0);
}
private:
mutable CounterBase *counter;
template <typename U> friend class RefCountPtr;
};
template <typename T>
void swap(RefCountPtr<T> &a, RefCountPtr<T> &b)
{
a.swap(b);
}
#endif // TAGLIB_USE_*_SHARED_PTR
}
#endif // DO_NOT_DOCUMENT
#endif

View File

@@ -23,8 +23,14 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "taglib_config.h"
#if !defined(TAGLIB_USE_STD_SHARED_PTR) \
&& !defined(TAGLIB_USE_TR1_SHARED_PTR) \
&& !defined(TAGLIB_USE_BOOST_SHARED_PTR)
#include "config.h"
#include "trefcountptr.h"
#include "tsmartptr.h"
#if defined(HAVE_STD_ATOMIC)
# include <atomic>
@@ -66,41 +72,44 @@
namespace TagLib
{
class RefCounter::RefCounterPrivate
class CounterBase::CounterBasePrivate
{
public:
RefCounterPrivate() : refCount(1) {}
size_t ref() { return static_cast<size_t>(ATOMIC_INC(refCount)); }
size_t deref() { return static_cast<size_t>(ATOMIC_DEC(refCount)); }
size_t count() const { return static_cast<size_t>(refCount); }
CounterBasePrivate()
: refCount(1)
{
}
volatile ATOMIC_INT refCount;
};
RefCounter::RefCounter()
: d(new RefCounterPrivate())
CounterBase::CounterBase()
: d(new CounterBasePrivate())
{
}
RefCounter::~RefCounter()
CounterBase::~CounterBase()
{
delete d;
}
size_t RefCounter::ref()
void CounterBase::addref()
{
return d->ref();
ATOMIC_INC(d->refCount);
}
size_t RefCounter::deref()
{
return d->deref();
void CounterBase::release()
{
if(ATOMIC_DEC(d->refCount) == 0) {
dispose();
delete this;
}
}
size_t RefCounter::count() const
{
return d->count();
long CounterBase::use_count() const
{
return static_cast<long>(d->refCount);
}
}
#endif

View File

@@ -27,28 +27,577 @@
#define TAGLIB_SMARTPTR_H
#include "taglib_config.h"
#include <algorithm>
#if defined(TAGLIB_USE_STD_SHARED_PTR)
# include <memory>
#elif defined(TAGLIB_USE_TR1_SHARED_PTR)
# include <tr1/memory>
#elif defined(TAGLIB_USE_BOOST_SHARED_PTR)
# include <boost/shared_ptr.hpp>
#else
# include "trefcountptr.h"
#endif
#if defined(TAGLIB_USE_STD_SHARED_PTR) || defined(TAGLIB_USE_TR1_SHARED_PTR)
# define TAGLIB_SHARED_PTR std::tr1::shared_ptr
#elif defined(TAGLIB_USE_BOOST_SHARED_PTR)
# define TAGLIB_SHARED_PTR boost::shared_ptr
#else
# define TAGLIB_SHARED_PTR TagLib::RefCountPtr
# include <boost/shared_ptr.hpp>
#endif
#if defined(TAGLIB_USE_STD_UNIQUE_PTR)
# include <memory>
#elif defined(TAGLIB_USE_BOOST_SCOPED_PTR)
# include <boost/scoped_ptr.hpp>
#endif
#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class.
/*!
* \warning This <b>is not</b> part of the TagLib public API!
*/
namespace TagLib
{
#if defined(TAGLIB_USE_STD_SHARED_PTR) \
|| defined(TAGLIB_USE_TR1_SHARED_PTR) \
|| defined(TAGLIB_USE_BOOST_SHARED_PTR)
// RefCountPtr<T> is just a thin wrapper of shared_ptr<T>.
// It will be optimized out by compilers and performs equivalent to them.
template <typename T>
class RefCountPtr
{
public:
RefCountPtr()
: sp()
{
}
template <typename U>
explicit RefCountPtr(U *p)
: sp(p)
{
}
RefCountPtr(const RefCountPtr<T> &x)
: sp(x.sp)
{
}
template <typename U>
RefCountPtr(const RefCountPtr<U> &x)
: sp(x.sp)
{
}
# ifdef TAGLIB_USE_MOVE_SEMANTICS
RefCountPtr(RefCountPtr<T> &&x)
: sp(std::move(x.sp))
{
}
template <typename U>
RefCountPtr(RefCountPtr<U> &&x)
: sp(std::move(x.sp))
{
}
# endif
T *get() const
{
return sp.get();
}
long use_count() const
{
return sp.use_count();
}
bool unique() const
{
return sp.unique();
}
template <typename U>
void reset(U *p)
{
sp.reset(p);
}
void reset()
{
sp.reset();
}
void swap(RefCountPtr<T> &x)
{
sp.swap(x.sp);
}
RefCountPtr<T> &operator=(const RefCountPtr<T> &x)
{
sp = x.sp;
return *this;
}
template <typename U>
RefCountPtr<T> &operator=(const RefCountPtr<U> &x)
{
sp = x.sp;
return *this;
}
# ifdef TAGLIB_USE_MOVE_SEMANTICS
RefCountPtr<T> &operator=(RefCountPtr<T> &&x)
{
sp = std::move(x.sp);
return *this;
}
template <typename U>
RefCountPtr<T> &operator=(RefCountPtr<U> &&x)
{
sp = std::move(x.sp);
return *this;
}
# endif
T& operator*() const
{
return sp.operator*();
}
T* operator->() const
{
return sp.operator->();
}
operator bool() const
{
return static_cast<bool>(sp);
}
bool operator!() const
{
return !static_cast<bool>(sp);
}
private:
template <typename U> friend class RefCountPtr;
# if defined(TAGLIB_USE_STD_SHARED_PTR)
std::shared_ptr<T> sp;
# elif defined(TAGLIB_USE_TR1_SHARED_PTR)
std::tr1::shared_ptr<T> sp;
# else
boost::shared_ptr<T> sp;
# endif
};
#else // TAGLIB_USE_STD_SHARED_PTR etc.
// Self-implements RefCountPtr<T> if shared_ptr<T> is not available.
// I STRONGLY RECOMMEND using standard shared_ptr<T> rather than this class.
// Counter base class. Provides a reference counter.
class CounterBase
{
public:
CounterBase();
virtual ~CounterBase();
void addref();
void release();
long use_count() const;
virtual void dispose() = 0;
private:
class CounterBasePrivate;
CounterBasePrivate *d;
};
// Counter impl class. Provides a dynamic deleter.
template <typename T>
class CounterImpl : public CounterBase
{
public:
CounterImpl(T *p)
: p(p)
{
}
virtual void dispose()
{
delete p;
}
T *get() const
{
return p;
}
private:
T *p;
};
template<typename T>
class RefCountPtr
{
public:
RefCountPtr()
: px(0)
, counter(0)
{
}
template <typename U>
explicit RefCountPtr(U *p)
: px(p)
, counter(new CounterImpl<U>(p))
{
}
RefCountPtr(const RefCountPtr<T> &x)
: px(x.px)
, counter(x.counter)
{
if(counter)
counter->addref();
}
template <typename U>
RefCountPtr(const RefCountPtr<U> &x)
: px(x.px)
, counter(x.counter)
{
if(counter)
counter->addref();
}
~RefCountPtr()
{
if(counter)
counter->release();
}
T *get() const
{
return px;
}
long use_count() const
{
if(counter)
return counter->use_count();
else
return 0;
}
bool unique() const
{
return (use_count() == 1);
}
template <typename U>
void reset(U *p)
{
if(px != p)
RefCountPtr<T>(p).swap(*this);
}
void reset()
{
RefCountPtr<T>().swap(*this);
}
void swap(RefCountPtr<T> &x)
{
std::swap(px, x.px);
std::swap(counter, x.counter);
}
RefCountPtr<T> &operator=(const RefCountPtr<T> &x)
{
if(px != x.px) {
if(counter)
counter->release();
px = x.px;
counter = x.counter;
if(counter)
counter->addref();
}
return *this;
}
template <typename U>
RefCountPtr<T> &operator=(const RefCountPtr<U> &x)
{
if(px != x.px) {
if(counter)
counter->release();
px = x.px;
counter = x.counter;
if(counter)
counter->addref();
}
return *this;
}
T& operator*() const
{
return *px;
}
T* operator->() const
{
return px;
}
operator bool() const
{
return (px != 0);
}
bool operator!() const
{
return (px == 0);
}
private:
T *px;
CounterBase *counter;
template <typename U> friend class RefCountPtr;
};
#endif // TAGLIB_USE_STD_SHARED_PTR etc.
#if defined(TAGLIB_USE_STD_UNIQUE_PTR) || defined(TAGLIB_USE_BOOST_SCOPED_PTR)
// NonRefCountPtr<T> is just a thin wrapper of unique_ptr<T> or scoped_ptr<T>.
// It will be optimized out by compilers and performs equivalent to them.
template<typename T>
class NonRefCountPtr
{
public:
explicit NonRefCountPtr(T *p = 0)
: up(p)
{
}
~NonRefCountPtr()
{
}
void reset(T *p = 0)
{
NonRefCountPtr<T>(p).swap(*this);
}
T &operator*() const
{
return up.operator*();
}
T *operator->() const
{
return up.operator->();
}
T *get() const
{
return up.get();
}
operator bool() const
{
return static_cast<bool>(up);
}
bool operator!() const
{
return !static_cast<bool>(up);
}
void swap(NonRefCountPtr &x)
{
up.swap(x.up);
}
private:
// Noncopyable
NonRefCountPtr(const NonRefCountPtr &);
NonRefCountPtr &operator=(const NonRefCountPtr &);
void operator==(const NonRefCountPtr &) const;
void operator!=(const NonRefCountPtr &) const;
# if defined(TAGLIB_USE_STD_UNIQUE_PTR)
std::unique_ptr<T> up;
# else
boost::scoped_ptr<T> up;
# endif
};
#else // TAGLIB_USE_STD_UNIQUE_PTR
// Self-implements NonRefCountPtr<T> if unique_ptr<T> is not available.
// I STRONGLY RECOMMEND using standard unique_ptr<T> rather than this class.
template<typename T>
class NonRefCountPtr
{
public:
explicit NonRefCountPtr(T *p = 0)
: px(p)
{
}
~NonRefCountPtr()
{
delete px;
}
void reset(T *p = 0)
{
NonRefCountPtr<T>(p).swap(*this);
}
T &operator*() const
{
return *px;
}
T *operator->() const
{
return px;
}
T *get() const
{
return px;
}
operator bool() const
{
return (px != 0);
}
bool operator!() const
{
return (px == 0);
}
void swap(NonRefCountPtr &x)
{
std::swap(px, x.px);
}
private:
// Noncopyable
NonRefCountPtr(const NonRefCountPtr &);
NonRefCountPtr &operator=(const NonRefCountPtr &);
void operator==(const NonRefCountPtr &) const;
void operator!=(const NonRefCountPtr &) const;
T *px;
};
#endif // TAGLIB_USE_STD_UNIQUE_PTR
// Comparison operators for smart pointers.
template <typename T, typename U>
bool operator==(const RefCountPtr<T> &a, const RefCountPtr<U> &b)
{
return (a.get() == b.get());
}
template <typename T, typename U>
bool operator!=(const RefCountPtr<T> &a, const RefCountPtr<U> &b)
{
return (a.get() != b.get());
}
template <typename T, typename U>
bool operator==(const RefCountPtr<T> &a, U *b)
{
return (a.get() == b);
}
template <typename T, typename U>
bool operator!=(const RefCountPtr<T> &a, U *b)
{
return (a.get() != b);
}
template <typename T, typename U>
bool operator==(const NonRefCountPtr<T> &a, U *b)
{
return (a.get() == b);
}
template <typename T, typename U>
bool operator!=(const NonRefCountPtr<T> &a, U *b)
{
return (a.get() != b);
}
template <typename T, typename U>
bool operator==(T *a, const RefCountPtr<U> &b)
{
return (a == b.get());
}
template <typename T, typename U>
bool operator!=(T *a, const RefCountPtr<U> &b)
{
return (a != b.get());
}
template <typename T, typename U>
bool operator==(T *a, const NonRefCountPtr<U> &b)
{
return (a == b.get());
}
template <typename T, typename U>
bool operator!=(T *a, const NonRefCountPtr<U> &b)
{
return (a != b.get());
}
template <typename T>
void swap(RefCountPtr<T> &a, RefCountPtr<T> &b)
{
a.swap(b);
}
template <typename T>
void swap(NonRefCountPtr<T> &a, NonRefCountPtr<T> &b)
{
a.swap(b);
}
}
#endif // DO_NOT_DOCUMENT
#endif

View File

@@ -25,14 +25,15 @@
// This class assumes that std::basic_string<T> has a contiguous and null-terminated buffer.
#include <cstring>
#include "config.h"
#include "tstring.h"
#include "tdebug.h"
#include "tstringlist.h"
#include <iostream>
#include <cstdio>
#include <cstring>
#if defined(HAVE_MSC_BYTESWAP)
# include <stdlib.h>
@@ -608,31 +609,30 @@ bool String::isAscii() const
String String::number(int n) // static
{
if(n == 0)
return String("0");
static const size_t BufferSize = 11; // Sufficient to store "-214748364".
static const char *Format = "%d";
String charStack;
char buffer[BufferSize];
int length;
bool negative = n < 0;
#if defined(HAVE_SNPRINTF)
if(negative)
n = n * -1;
length = snprintf(buffer, BufferSize, Format, n);
while(n > 0) {
int remainder = n % 10;
charStack += char(remainder + '0');
n = (n - remainder) / 10;
}
#elif defined(HAVE_SPRINTF_S)
String s;
length = sprintf_s(buffer, Format, n);
if(negative)
s += '-';
#else
for(int i = static_cast<int>(charStack.d->data.size()) - 1; i >= 0; i--)
s += charStack.d->data[i];
length = sprintf(buffer, Format, n);
return s;
#endif
if(length > 0)
return String(buffer);
else
return String::null;
}
TagLib::wchar &String::operator[](size_t i)

View File

@@ -520,7 +520,7 @@ namespace TagLib {
static const Type WCharByteOrder;
class StringPrivate;
TAGLIB_SHARED_PTR<StringPrivate> d;
RefCountPtr<StringPrivate> d;
};
/*!

View File

@@ -120,8 +120,11 @@ TagLib::uint WavPack::AudioProperties::sampleFrames() const
// private members
////////////////////////////////////////////////////////////////////////////////
static const unsigned int sample_rates[] = { 6000, 8000, 9600, 11025, 12000,
namespace
{
const unsigned int sample_rates[] = { 6000, 8000, 9600, 11025, 12000,
16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 };
}
#define BYTES_STORED 3
#define MONO_FLAG 4

View File

@@ -62,294 +62,298 @@ using TagLib::ushort;
* Maybe if this is useful to other formats these classes can be moved to
* their own public files.
*/
class Reader
namespace
{
public:
virtual ~Reader()
class Reader
{
}
/*!
* Reads associated values from \a file, but never reads more
* then \a limit bytes.
*/
virtual uint read(TagLib::File &file, uint limit) = 0;
/*!
* Returns the number of bytes this reader would like to read.
*/
virtual uint size() const = 0;
};
class SkipReader : public Reader
{
public:
SkipReader(uint size) : m_size(size)
{
}
uint read(TagLib::File &file, uint limit)
{
uint count = std::min(m_size, limit);
file.seek(count, TagLib::File::Current);
return count;
}
uint size() const
{
return m_size;
}
private:
uint m_size;
};
template<typename T>
class ValueReader : public Reader
{
public:
ValueReader(T &value) : value(value)
{
}
protected:
T &value;
};
class StringReader : public ValueReader<String>
{
public:
StringReader(String &string, uint size) :
ValueReader<String>(string), m_size(size)
{
}
uint read(TagLib::File &file, uint limit)
{
ByteVector data = file.readBlock(std::min(m_size, limit));
size_t count = data.size();
const size_t index = data.find((char) 0);
if(index != ByteVector::npos) {
data.resize(index);
public:
virtual ~Reader()
{
}
data.replace((char) 0xff, ' ');
value = data;
return static_cast<uint>(count);
}
uint size() const
/*!
* Reads associated values from \a file, but never reads more
* then \a limit bytes.
*/
virtual uint read(TagLib::File &file, uint limit) = 0;
/*!
* Returns the number of bytes this reader would like to read.
*/
virtual uint size() const = 0;
};
class SkipReader : public Reader
{
return m_size;
}
private:
uint m_size;
};
class ByteReader : public ValueReader<uchar>
{
public:
ByteReader(uchar &byte) : ValueReader<uchar>(byte) {}
uint read(TagLib::File &file, uint limit)
{
ByteVector data = file.readBlock(std::min(1U,limit));
if(data.size() > 0) {
value = data[0];
public:
SkipReader(uint size) : m_size(size)
{
}
return static_cast<uint>(data.size());
}
uint size() const
{
return 1;
}
};
template<typename T>
class NumberReader : public ValueReader<T>
{
public:
NumberReader(T &value, bool bigEndian) :
ValueReader<T>(value), bigEndian(bigEndian)
{
}
protected:
bool bigEndian;
};
class U16Reader : public NumberReader<ushort>
{
public:
U16Reader(ushort &value, bool bigEndian)
: NumberReader<ushort>(value, bigEndian) {}
uint read(TagLib::File &file, uint limit)
{
ByteVector data = file.readBlock(std::min(2U,limit));
if(bigEndian)
value = data.toUInt16BE(0);
else
value = data.toUInt16LE(0);
return static_cast<uint>(data.size());
}
uint size() const
{
return 2;
}
};
class U32Reader : public NumberReader<uint>
{
public:
U32Reader(uint &value, bool bigEndian = true) :
NumberReader<uint>(value, bigEndian)
{
}
uint read(TagLib::File &file, uint limit)
{
ByteVector data = file.readBlock(std::min(4U,limit));
if(bigEndian)
value = data.toUInt32BE(0);
else
value = data.toUInt32LE(0);
return static_cast<uint>(data.size());
}
uint size() const
{
return 4;
}
};
class StructReader : public Reader
{
public:
StructReader()
{
m_readers.setAutoDelete(true);
}
/*!
* Add a nested reader. This reader takes ownership.
*/
StructReader &reader(Reader *reader)
{
m_readers.append(reader);
return *this;
}
/*!
* Don't read anything but skip \a size bytes.
*/
StructReader &skip(uint size)
{
m_readers.append(new SkipReader(size));
return *this;
}
/*!
* Read a string of \a size characters (bytes) into \a string.
*/
StructReader &string(String &string, uint size)
{
m_readers.append(new StringReader(string, size));
return *this;
}
/*!
* Read a byte into \a byte.
*/
StructReader &byte(uchar &byte)
{
m_readers.append(new ByteReader(byte));
return *this;
}
/*!
* Read a unsigned 16 Bit integer into \a number. The byte order
* is controlled by \a bigEndian.
*/
StructReader &u16(ushort &number, bool bigEndian)
{
m_readers.append(new U16Reader(number, bigEndian));
return *this;
}
/*!
* Read a unsigned 16 Bit little endian integer into \a number.
*/
StructReader &u16L(ushort &number)
{
return u16(number, false);
}
/*!
* Read a unsigned 16 Bit big endian integer into \a number.
*/
StructReader &u16B(ushort &number)
{
return u16(number, true);
}
/*!
* Read a unsigned 32 Bit integer into \a number. The byte order
* is controlled by \a bigEndian.
*/
StructReader &u32(uint &number, bool bigEndian)
{
m_readers.append(new U32Reader(number, bigEndian));
return *this;
}
/*!
* Read a unsigned 32 Bit little endian integer into \a number.
*/
StructReader &u32L(uint &number)
{
return u32(number, false);
}
/*!
* Read a unsigned 32 Bit big endian integer into \a number.
*/
StructReader &u32B(uint &number)
{
return u32(number, true);
}
uint size() const
{
uint size = 0;
for(List<Reader*>::ConstIterator i = m_readers.begin();
i != m_readers.end(); ++ i) {
size += (*i)->size();
uint read(TagLib::File &file, uint limit)
{
uint count = std::min(m_size, limit);
file.seek(count, TagLib::File::Current);
return count;
}
return size;
}
uint read(TagLib::File &file, uint limit)
{
uint sumcount = 0;
for(List<Reader*>::Iterator i = m_readers.begin();
limit > 0 && i != m_readers.end(); ++ i) {
uint count = (*i)->read(file, limit);
limit -= count;
sumcount += count;
uint size() const
{
return m_size;
}
return sumcount;
}
private:
List<Reader*> m_readers;
};
private:
uint m_size;
};
template<typename T>
class ValueReader : public Reader
{
public:
ValueReader(T &value) : value(value)
{
}
protected:
T &value;
};
class StringReader : public ValueReader<String>
{
public:
StringReader(String &string, uint size) :
ValueReader<String>(string), m_size(size)
{
}
uint read(TagLib::File &file, uint limit)
{
ByteVector data = file.readBlock(std::min(m_size, limit));
size_t count = data.size();
const size_t index = data.find((char) 0);
if(index != ByteVector::npos) {
data.resize(index);
}
data.replace((char) 0xff, ' ');
value = data;
return static_cast<uint>(count);
}
uint size() const
{
return m_size;
}
private:
uint m_size;
};
class ByteReader : public ValueReader<uchar>
{
public:
ByteReader(uchar &byte) : ValueReader<uchar>(byte) {}
uint read(TagLib::File &file, uint limit)
{
ByteVector data = file.readBlock(std::min(1U,limit));
if(data.size() > 0) {
value = data[0];
}
return static_cast<uint>(data.size());
}
uint size() const
{
return 1;
}
};
template<typename T>
class NumberReader : public ValueReader<T>
{
public:
NumberReader(T &value, bool bigEndian) :
ValueReader<T>(value), bigEndian(bigEndian)
{
}
protected:
bool bigEndian;
};
class U16Reader : public NumberReader<ushort>
{
public:
U16Reader(ushort &value, bool bigEndian)
: NumberReader<ushort>(value, bigEndian) {}
uint read(TagLib::File &file, uint limit)
{
ByteVector data = file.readBlock(std::min(2U,limit));
if(bigEndian)
value = data.toUInt16BE(0);
else
value = data.toUInt16LE(0);
return static_cast<uint>(data.size());
}
uint size() const
{
return 2;
}
};
class U32Reader : public NumberReader<uint>
{
public:
U32Reader(uint &value, bool bigEndian = true) :
NumberReader<uint>(value, bigEndian)
{
}
uint read(TagLib::File &file, uint limit)
{
ByteVector data = file.readBlock(std::min(4U,limit));
if(bigEndian)
value = data.toUInt32BE(0);
else
value = data.toUInt32LE(0);
return static_cast<uint>(data.size());
}
uint size() const
{
return 4;
}
};
class StructReader : public Reader
{
public:
StructReader()
{
m_readers.setAutoDelete(true);
}
/*!
* Add a nested reader. This reader takes ownership.
*/
StructReader &reader(Reader *reader)
{
m_readers.append(reader);
return *this;
}
/*!
* Don't read anything but skip \a size bytes.
*/
StructReader &skip(uint size)
{
m_readers.append(new SkipReader(size));
return *this;
}
/*!
* Read a string of \a size characters (bytes) into \a string.
*/
StructReader &string(String &string, uint size)
{
m_readers.append(new StringReader(string, size));
return *this;
}
/*!
* Read a byte into \a byte.
*/
StructReader &byte(uchar &byte)
{
m_readers.append(new ByteReader(byte));
return *this;
}
/*!
* Read a unsigned 16 Bit integer into \a number. The byte order
* is controlled by \a bigEndian.
*/
StructReader &u16(ushort &number, bool bigEndian)
{
m_readers.append(new U16Reader(number, bigEndian));
return *this;
}
/*!
* Read a unsigned 16 Bit little endian integer into \a number.
*/
StructReader &u16L(ushort &number)
{
return u16(number, false);
}
/*!
* Read a unsigned 16 Bit big endian integer into \a number.
*/
StructReader &u16B(ushort &number)
{
return u16(number, true);
}
/*!
* Read a unsigned 32 Bit integer into \a number. The byte order
* is controlled by \a bigEndian.
*/
StructReader &u32(uint &number, bool bigEndian)
{
m_readers.append(new U32Reader(number, bigEndian));
return *this;
}
/*!
* Read a unsigned 32 Bit little endian integer into \a number.
*/
StructReader &u32L(uint &number)
{
return u32(number, false);
}
/*!
* Read a unsigned 32 Bit big endian integer into \a number.
*/
StructReader &u32B(uint &number)
{
return u32(number, true);
}
uint size() const
{
uint size = 0;
for(List<Reader*>::ConstIterator i = m_readers.begin();
i != m_readers.end(); ++ i) {
size += (*i)->size();
}
return size;
}
uint read(TagLib::File &file, uint limit)
{
uint sumcount = 0;
for(List<Reader*>::Iterator i = m_readers.begin();
limit > 0 && i != m_readers.end(); ++ i) {
uint count = (*i)->read(file, limit);
limit -= count;
sumcount += count;
}
return sumcount;
}
private:
List<Reader*> m_readers;
};
}
class XM::File::FilePrivate
{

View File

@@ -163,10 +163,6 @@ public:
CPPUNIT_ASSERT(n.toInt64LE(6) == -1268082884489200845ll);
CPPUNIT_ASSERT(n.toInt64BE(4) == 2497865822736504285ll);
// Shows the message "toNumber<T>() -- offset is out of range. Returning 0." 2 times.
CPPUNIT_ASSERT(n.toUInt32LE(13) == 0);
CPPUNIT_ASSERT(n.toUInt16BE(15) == 0);
CPPUNIT_ASSERT(ByteVector::fromUInt16LE(n.toInt16LE(5)) == n.mid(5, 2));
CPPUNIT_ASSERT(ByteVector::fromUInt16BE(n.toInt16BE(9)) == n.mid(9, 2));
CPPUNIT_ASSERT(ByteVector::fromUInt32LE(n.toUInt32LE(4)) == n.mid(4, 4));

View File

@@ -37,6 +37,7 @@ public:
string newname = copy.fileName();
FileRef *f = new FileRef(newname.c_str());
CPPUNIT_ASSERT(f->isValid());
CPPUNIT_ASSERT(!f->isNull());
f->tag()->setArtist("test artist");
f->tag()->setTitle("test title");
@@ -48,6 +49,7 @@ public:
delete f;
f = new FileRef(newname.c_str());
CPPUNIT_ASSERT(f->isValid());
CPPUNIT_ASSERT(!f->isNull());
CPPUNIT_ASSERT_EQUAL(f->tag()->artist(), String("test artist"));
CPPUNIT_ASSERT_EQUAL(f->tag()->title(), String("test title"));
@@ -65,6 +67,7 @@ public:
delete f;
f = new FileRef(newname.c_str());
CPPUNIT_ASSERT(f->isValid());
CPPUNIT_ASSERT(!f->isNull());
CPPUNIT_ASSERT_EQUAL(f->tag()->artist(), String("ttest artist"));
CPPUNIT_ASSERT_EQUAL(f->tag()->title(), String("ytest title"));
@@ -73,6 +76,27 @@ public:
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());
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();
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()

View File

@@ -1,5 +1,6 @@
#include <string>
#include <stdio.h>
#include <config.h>
// so evil :(
#define protected public
#include <id3v2tag.h>
@@ -15,6 +16,7 @@
#include <popularimeterframe.h>
#include <urllinkframe.h>
#include <ownershipframe.h>
#include <unknownframe.h>
#include <tdebug.h>
#include <tpropertymap.h>
#include <cppunit/extensions/HelperMacros.h>
@@ -582,13 +584,27 @@ public:
{
MPEG::File f(TEST_FILE_PATH_C("compressed_id3_frame.mp3"), false);
CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("APIC"));
ID3v2::AttachedPictureFrame *frame =
static_cast<TagLib::ID3v2::AttachedPictureFrame*>(f.ID3v2Tag()->frameListMap()["APIC"].front());
#ifdef HAVE_ZLIB
ID3v2::AttachedPictureFrame *frame
= dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(f.ID3v2Tag()->frameListMap()["APIC"].front());
CPPUNIT_ASSERT(frame);
CPPUNIT_ASSERT_EQUAL(String("image/bmp"), frame->mimeType());
CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, frame->type());
CPPUNIT_ASSERT_EQUAL(String(""), frame->description());
CPPUNIT_ASSERT_EQUAL(size_t(86414), frame->picture().size());
#else
// Skip the test if ZLIB is not installed.
// The message "Compressed frames are currently not supported." will be displayed.
ID3v2::UnknownFrame *frame
= dynamic_cast<TagLib::ID3v2::UnknownFrame*>(f.ID3v2Tag()->frameListMap()["APIC"].front());
CPPUNIT_ASSERT(frame);
#endif
}
void testW000()

View File

@@ -26,7 +26,7 @@ public:
void testSharedptrBasic()
{
int * ip = new int;
TAGLIB_SHARED_PTR<int> cp ( ip );
RefCountPtr<int> cp ( ip );
CPPUNIT_ASSERT( ip == cp.get() );
CPPUNIT_ASSERT( cp.use_count() == 1 );
@@ -36,7 +36,7 @@ public:
ck( static_cast<int*>(cp.get()), 54321 );
ck( static_cast<int*>(ip), *cp );
TAGLIB_SHARED_PTR<int> cp2 ( cp );
RefCountPtr<int> cp2 ( cp );
CPPUNIT_ASSERT( ip == cp2.get() );
CPPUNIT_ASSERT( cp.use_count() == 2 );
CPPUNIT_ASSERT( cp2.use_count() == 2 );
@@ -46,7 +46,7 @@ public:
ck( static_cast<int*>(cp2.get()), 54321 );
ck( static_cast<int*>(ip), *cp2 );
TAGLIB_SHARED_PTR<int> cp3 ( cp );
RefCountPtr<int> cp3 ( cp );
CPPUNIT_ASSERT( cp.use_count() == 3 );
CPPUNIT_ASSERT( cp2.use_count() == 3 );
CPPUNIT_ASSERT( cp3.use_count() == 3 );
@@ -76,16 +76,16 @@ public:
CPPUNIT_ASSERT( cp.use_count() == 3 );
CPPUNIT_ASSERT( *cp == 87654 );
TAGLIB_SHARED_PTR<int> cp4;
RefCountPtr<int> cp4;
swap( cp2, cp4 );
CPPUNIT_ASSERT( cp4.use_count() == 3 );
CPPUNIT_ASSERT( *cp4 == 87654 );
CPPUNIT_ASSERT( cp2.get() == 0 );
std::set< TAGLIB_SHARED_PTR<int> > scp;
std::set< RefCountPtr<int> > scp;
scp.insert(cp4);
CPPUNIT_ASSERT( scp.find(cp4) != scp.end() );
CPPUNIT_ASSERT( scp.find(cp4) == scp.find( TAGLIB_SHARED_PTR<int>(cp4) ) );
CPPUNIT_ASSERT( scp.find(cp4) == scp.find( RefCountPtr<int>(cp4) ) );
}
private:
@@ -130,7 +130,7 @@ public:
derivedDestructorCalled = false;
{
TAGLIB_SHARED_PTR<DummyBase> p1(new DummyDerived(100));
RefCountPtr<DummyBase> p1(new DummyDerived(100));
CPPUNIT_ASSERT(p1->getValue() == 100);
}
@@ -141,8 +141,8 @@ public:
derivedDestructorCalled = false;
{
TAGLIB_SHARED_PTR<DummyDerived> p1(new DummyDerived(100));
TAGLIB_SHARED_PTR<DummyBase> p2 = p1;
RefCountPtr<DummyDerived> p1(new DummyDerived(100));
RefCountPtr<DummyBase> p2 = p1;
CPPUNIT_ASSERT(p1->getValue() == 100);
CPPUNIT_ASSERT(p2->getValue() == 100);
@@ -155,8 +155,8 @@ public:
derivedDestructorCalled = false;
{
TAGLIB_SHARED_PTR<DummyDerived> p1;
TAGLIB_SHARED_PTR<DummyBase> p2;
RefCountPtr<DummyDerived> p1;
RefCountPtr<DummyBase> p2;
p1.reset(new DummyDerived(100));
p2 = p1;
@@ -171,7 +171,7 @@ public:
private:
class DummyIncomplete;
TAGLIB_SHARED_PTR<DummyIncomplete> pincomplete;
RefCountPtr<DummyIncomplete> pincomplete;
class DummyIncomplete
{