mirror of
https://github.com/taglib/taglib.git
synced 2026-06-13 01:39:17 -04:00
Merge remote-tracking branch 'correct/taglib2' into taglib2
This commit is contained in:
2
AUTHORS
2
AUTHORS
@@ -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!
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -231,7 +231,7 @@ namespace TagLib
|
||||
#endif
|
||||
private:
|
||||
class PicturePrivate;
|
||||
TAGLIB_SHARED_PTR<PicturePrivate> d;
|
||||
RefCountPtr<PicturePrivate> d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace TagLib {
|
||||
|
||||
private:
|
||||
class CoverArtPrivate;
|
||||
TAGLIB_SHARED_PTR<CoverArtPrivate> d;
|
||||
RefCountPtr<CoverArtPrivate> d;
|
||||
};
|
||||
|
||||
typedef List<CoverArt> CoverArtList;
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace TagLib {
|
||||
|
||||
private:
|
||||
class ItemPrivate;
|
||||
TAGLIB_SHARED_PTR<ItemPrivate> d;
|
||||
RefCountPtr<ItemPrivate> d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace TagLib {
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
class HeaderPrivate;
|
||||
TAGLIB_SHARED_PTR<HeaderPrivate> d;
|
||||
RefCountPtr<HeaderPrivate> d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace TagLib {
|
||||
void read(const ByteVector &data);
|
||||
|
||||
class PropertiesPrivate;
|
||||
TAGLIB_SHARED_PTR<PropertiesPrivate> d;
|
||||
RefCountPtr<PropertiesPrivate> d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace TagLib {
|
||||
TagUnion &operator=(const Tag &);
|
||||
|
||||
class TagUnionPrivate;
|
||||
TAGLIB_SHARED_PTR<TagUnionPrivate> d;
|
||||
NonRefCountPtr<TagUnionPrivate> d;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -551,7 +551,7 @@ namespace TagLib {
|
||||
|
||||
private:
|
||||
class ByteVectorPrivate;
|
||||
TAGLIB_SHARED_PTR<ByteVectorPrivate> d;
|
||||
RefCountPtr<ByteVectorPrivate> d;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
@@ -27,11 +27,6 @@
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ByteVectorListPrivate
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -520,7 +520,7 @@ namespace TagLib {
|
||||
static const Type WCharByteOrder;
|
||||
|
||||
class StringPrivate;
|
||||
TAGLIB_SHARED_PTR<StringPrivate> d;
|
||||
RefCountPtr<StringPrivate> d;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user