diff --git a/Frameworks/TagLib/TagLib.xcodeproj/project.pbxproj b/Frameworks/TagLib/TagLib.xcodeproj/project.pbxproj index b5463c5ed..6e77e2284 100644 --- a/Frameworks/TagLib/TagLib.xcodeproj/project.pbxproj +++ b/Frameworks/TagLib/TagLib.xcodeproj/project.pbxproj @@ -152,6 +152,8 @@ 4872B8881A675CCB00674347 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4872B8871A675CCB00674347 /* libiconv.dylib */; }; 83790D241809E8CA0073CF51 /* opusfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83790D201809E8CA0073CF51 /* opusfile.cpp */; }; 83790D261809E8CA0073CF51 /* opusproperties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83790D221809E8CA0073CF51 /* opusproperties.cpp */; }; + 83AF2CBE2622643300538240 /* apegenfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83AF2CBC2622643300538240 /* apegenfile.cpp */; }; + 83AF2CBF2622643300538240 /* apegenfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AF2CBD2622643300538240 /* apegenfile.h */; }; 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; EDE862FD25CF6BD70086EFD3 /* tpropertymap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDE862FC25CF6BD60086EFD3 /* tpropertymap.cpp */; }; EDE8630225CF6C260086EFD3 /* tfilestream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDE8630025CF6C260086EFD3 /* tfilestream.cpp */; }; @@ -362,6 +364,8 @@ 83790D211809E8CA0073CF51 /* opusfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opusfile.h; sourceTree = ""; }; 83790D221809E8CA0073CF51 /* opusproperties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opusproperties.cpp; sourceTree = ""; }; 83790D231809E8CA0073CF51 /* opusproperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opusproperties.h; sourceTree = ""; }; + 83AF2CBC2622643300538240 /* apegenfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = apegenfile.cpp; sourceTree = ""; }; + 83AF2CBD2622643300538240 /* apegenfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apegenfile.h; sourceTree = ""; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8DC2EF5B0486A6940098B216 /* TagLib.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TagLib.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EDE862FC25CF6BD60086EFD3 /* tpropertymap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tpropertymap.cpp; sourceTree = ""; }; @@ -586,6 +590,8 @@ 32AE59A514E70ED600420CA0 /* apefile.h */, 32AE59A614E70ED600420CA0 /* apefooter.cpp */, 32AE59A714E70ED600420CA0 /* apefooter.h */, + 83AF2CBC2622643300538240 /* apegenfile.cpp */, + 83AF2CBD2622643300538240 /* apegenfile.h */, 32AE59A814E70ED600420CA0 /* apeitem.cpp */, 32AE59A914E70ED600420CA0 /* apeitem.h */, 32AE59AA14E70ED600420CA0 /* apeproperties.cpp */, @@ -1108,6 +1114,7 @@ 32AE5AAF14E70ED600420CA0 /* id3v2footer.h in Headers */, 32AE5AB114E70ED600420CA0 /* id3v2frame.h in Headers */, 32AE5AB314E70ED600420CA0 /* id3v2framefactory.h in Headers */, + 83AF2CBF2622643300538240 /* apegenfile.h in Headers */, 32AE5AB514E70ED600420CA0 /* id3v2header.h in Headers */, 32AE5AB714E70ED600420CA0 /* id3v2synchdata.h in Headers */, 32AE5AB914E70ED600420CA0 /* id3v2tag.h in Headers */, @@ -1241,6 +1248,7 @@ EDE8630725CF6C5B0086EFD3 /* itfile.cpp in Sources */, 32AE5A7614E70ED600420CA0 /* flacmetadatablock.cpp in Sources */, 32AE5A7814E70ED600420CA0 /* flacpicture.cpp in Sources */, + 83AF2CBE2622643300538240 /* apegenfile.cpp in Sources */, 32AE5A7A14E70ED600420CA0 /* flacproperties.cpp in Sources */, EDE863C625CF6D710086EFD3 /* ownershipframe.cpp in Sources */, 32AE5A7C14E70ED600420CA0 /* flacunknownmetadatablock.cpp in Sources */, diff --git a/Frameworks/TagLib/taglib/taglib/ape/apegenfile.cpp b/Frameworks/TagLib/taglib/taglib/ape/apegenfile.cpp new file mode 100644 index 000000000..b47282ed5 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/ape/apegenfile.cpp @@ -0,0 +1,204 @@ +/*************************************************************************** + copyright : (C) 2010 by Alex Novichkov + email : novichko@atnet.ru + + copyright : (C) 2006 by Lukáš Lalinský + email : lalinsky@gmail.com + (original WavPack implementation) + + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + (original MPC implementation) + ***************************************************************************/ + +/*************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version * + * 2.1 as published by the Free Software Foundation. * + * * + * This library is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * + * 02110-1301 USA * + * * + * Alternatively, this file is available under the Mozilla Public * + * License Version 1.1. You may obtain a copy of the License at * + * http://www.mozilla.org/MPL/ * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apegenfile.h" +#include "apetag.h" +#include "apefooter.h" + +using namespace TagLib; + +namespace +{ + enum { ApeGenAPEIndex = 0 }; +} + +class APEGen::File::FilePrivate +{ +public: + FilePrivate() : + APELocation(-1), + APESize(0) {} + + ~FilePrivate() + { + } + + long APELocation; + long APESize; + + TagUnion tag; +}; + +//////////////////////////////////////////////////////////////////////////////// +// static members +//////////////////////////////////////////////////////////////////////////////// + +bool APEGen::File::isSupported(IOStream *stream) +{ + // Generic file support for anything with APE tags + const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true); + return (buffer.find("APETAGEX") >= 0); +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +APEGen::File::File(FileName file, bool readProperties, Properties::ReadStyle) : + TagLib::File(file), + d(new FilePrivate()) +{ + if(isOpen()) + read(readProperties); +} + +APEGen::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) : + TagLib::File(stream), + d(new FilePrivate()) +{ + if(isOpen()) + read(readProperties); +} + +APEGen::File::~File() +{ + delete d; +} + +TagLib::Tag *APEGen::File::tag() const +{ + return &d->tag; +} + +PropertyMap APEGen::File::properties() const +{ + return d->tag.properties(); +} + +void APEGen::File::removeUnsupportedProperties(const StringList &properties) +{ + d->tag.removeUnsupportedProperties(properties); +} + +PropertyMap APEGen::File::setProperties(const PropertyMap &properties) +{ + return APETag(true)->setProperties(properties); +} + +APEGen::Properties *APEGen::File::audioProperties() const +{ + return NULL; +} + +bool APEGen::File::save() +{ + if(readOnly()) { + debug("APEGen::File::save() -- File is read only."); + return false; + } + + // Update APE tag + + if(APETag() && !APETag()->isEmpty()) { + + // APE tag is not empty. Update the old one or create a new one. + + if(d->APELocation < 0) { + d->APELocation = length(); + } + + const ByteVector data = APETag()->render(); + insert(data, d->APELocation, d->APESize); + + d->APESize = data.size(); + } + else { + + // APE tag is empty. Remove the old one. + + if(d->APELocation >= 0) { + removeBlock(d->APELocation, d->APESize); + + d->APELocation = -1; + d->APESize = 0; + } + } + + return true; +} + +APE::Tag *APEGen::File::APETag(bool create) +{ + return d->tag.access(ApeGenAPEIndex, create); +} + +void APEGen::File::strip(int tags) +{ + if(tags & APE) + d->tag.set(ApeGenAPEIndex, 0); + + APETag(true); +} + +bool APEGen::File::hasAPETag() const +{ + return (d->APELocation >= 0); +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void APEGen::File::read(bool readProperties) +{ + // Look for an APE tag + + d->APELocation = Utils::findAPE(this, -1); + + if(d->APELocation >= 0) { + d->tag.set(ApeGenAPEIndex, new APE::Tag(this, d->APELocation)); + d->APESize = APETag()->footer()->completeTagSize(); + d->APELocation = d->APELocation + APE::Footer::size() - d->APESize; + } + + APETag(true); +} diff --git a/Frameworks/TagLib/taglib/taglib/ape/apegenfile.h b/Frameworks/TagLib/taglib/taglib/ape/apegenfile.h new file mode 100644 index 000000000..5f2262e12 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/ape/apegenfile.h @@ -0,0 +1,201 @@ +/*************************************************************************** + copyright : (C) 2010 by Alex Novichkov + email : novichko@atnet.ru + + copyright : (C) 2006 by Lukáš Lalinský + email : lalinsky@gmail.com + (original WavPack implementation) + + copyright : (C) 2004 by Allan Sandfeld Jensen + email : kde@carewolf.org + (original MPC implementation) + ***************************************************************************/ + +/*************************************************************************** + * 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_APEGENFILE_H +#define TAGLIB_APEGENFILE_H + +#include "tfile.h" +#include "taglib_export.h" +#include "apeproperties.h" + +namespace TagLib { + + class Tag; + + namespace APE { class Tag; } + + //! An implementation of APE metadata + + /*! + * This is implementation of APE metadata. + * + * This supports APE (v1 and v2) style comments only. + */ + + namespace APEGen { + + class Properties : public APE::Properties { }; + + //! An implementation of TagLib::File with APE specific methods + + /*! + * This implements and provides an interface for any arbitrary file with + * APE tags appended, and no other tag format, using TagLib::Tag and + * TagLib::AudioProperties interfaces by way of implementing the abstract + * TagLib::File API as well as providing some additional information + * specific to APE tagged files. No technical info supported. + */ + + class TAGLIB_EXPORT File : public TagLib::File + { + public: + /*! + * This set of flags is used for various operations and is suitable for + * being OR-ed together. + */ + enum TagTypes { + //! Empty set. Matches no tag types. + NoTags = 0x0000, + //! Matches APE tags. + APE = 0x0001, + //! Matches all tag types. + AllTags = 0xffff + }; + + /*! + * Constructs an APE file from \a file. If \a readProperties is true the + * file's audio properties will also be read. + * + * \note In the current implementation, \a propertiesStyle is ignored. + */ + File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Constructs an APE file from \a stream. If \a readProperties is true the + * file's audio properties will also be read. + * + * \note TagLib will *not* take ownership of the stream, the caller is + * responsible for deleting it after the File object. + * + * \note In the current implementation, \a propertiesStyle is ignored. + */ + File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Destroys this instance of the File. + */ + virtual ~File(); + + /*! + * Returns the Tag for this file. This will be an APE tag. + */ + virtual TagLib::Tag *tag() const; + + /*! + * Implements the unified property interface -- export function. + */ + PropertyMap properties() const; + + /*! + * Removes unsupported properties. Forwards to the actual Tag's + * removeUnsupportedProperties() function. + */ + void removeUnsupportedProperties(const StringList &properties); + + /*! + * Implements the unified property interface -- import function. + * Creates an APEv2 tag if necessary. + */ + PropertyMap setProperties(const PropertyMap &); + + /*! + * Returns the APE::Properties for this file. If no audio properties + * were read then this will return a null pointer. + */ + virtual Properties *audioProperties() const; + + /*! + * Saves the file. + * + * Updates an existing APE tag, adds a new APEv2 tag, or removes it. + */ + virtual bool save(); + + /*! + * Returns a pointer to the APE tag of the file. + * + * If \a create is false (the default) this may return a null pointer + * if there is no valid APE tag. If \a create is true it will create + * an APE tag if one does not exist and returns a valid pointer. + * + * \note This may return a valid pointer regardless of whether or not the + * file on disk has an APE tag. Use hasAPETag() to check if the file + * on disk actually has an APE tag. + * + * \note The Tag is still owned by the MPEG::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + * + * \see hasAPETag() + */ + APE::Tag *APETag(bool create = false); + + /*! + * This will remove the tags that match the OR-ed together TagTypes from the + * file. By default it removes all tags. + * + * \note This will also invalidate pointers to the tags + * as their memory will be freed. + * \note In order to make the removal permanent save() still needs to be called + */ + void strip(int tags = AllTags); + + /*! + * Returns whether or not the file on disk actually has an APE tag. + * + * \see APETag() + */ + bool hasAPETag() const; + + /*! + * Returns whether or not the given \a stream can be opened using an + * APE tag parser. Does no other validation. + * + * \note This method is designed to do a quick check. The result may + * not necessarily be correct. + */ + static bool isSupported(IOStream *stream); + + private: + File(const File &); + File &operator=(const File &); + + void read(bool readProperties); + + class FilePrivate; + FilePrivate *d; + }; + } +} + +#endif diff --git a/Frameworks/TagLib/taglib/taglib/fileref.cpp b/Frameworks/TagLib/taglib/taglib/fileref.cpp index 0f392ec73..2aab81e94 100644 --- a/Frameworks/TagLib/taglib/taglib/fileref.cpp +++ b/Frameworks/TagLib/taglib/taglib/fileref.cpp @@ -50,6 +50,7 @@ #include "aifffile.h" #include "wavfile.h" #include "apefile.h" +#include "apegenfile.h" #include "modfile.h" #include "s3mfile.h" #include "itfile.h" @@ -139,6 +140,8 @@ namespace return new IT::File(stream, readAudioProperties, audioPropertiesStyle); if(ext == "XM") return new XM::File(stream, readAudioProperties, audioPropertiesStyle); + if(ext == "TAK") + return new APEGen::File(stream, readAudioProperties, audioPropertiesStyle); return 0; } @@ -178,6 +181,8 @@ namespace file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle); else if(APE::File::isSupported(stream)) file = new APE::File(stream, readAudioProperties, audioPropertiesStyle); + else if(APEGen::File::isSupported(stream)) + file = new APEGen::File(stream, readAudioProperties, audioPropertiesStyle); // isSupported() only does a quick check, so double check the file here. @@ -259,6 +264,8 @@ namespace return new IT::File(fileName, readAudioProperties, audioPropertiesStyle); if(ext == "XM") return new XM::File(fileName, readAudioProperties, audioPropertiesStyle); + if(ext == "TAK") + return new APEGen::File(fileName, readAudioProperties, audioPropertiesStyle); return 0; } diff --git a/Frameworks/TagLib/taglib/taglib/toolkit/tfile.cpp b/Frameworks/TagLib/taglib/taglib/toolkit/tfile.cpp index aff1684d9..43bb0d28f 100644 --- a/Frameworks/TagLib/taglib/taglib/toolkit/tfile.cpp +++ b/Frameworks/TagLib/taglib/taglib/toolkit/tfile.cpp @@ -58,6 +58,7 @@ #include "aifffile.h" #include "wavfile.h" #include "apefile.h" +#include "apegenfile.h" #include "modfile.h" #include "s3mfile.h" #include "itfile.h" @@ -148,6 +149,8 @@ PropertyMap File::properties() const return dynamic_cast(this)->properties(); if(dynamic_cast(this)) return dynamic_cast(this)->properties(); + if(dynamic_cast(this)) + return dynamic_cast(this)->properties(); return tag()->properties(); } @@ -177,6 +180,8 @@ void File::removeUnsupportedProperties(const StringList &properties) dynamic_cast(this)->removeUnsupportedProperties(properties); else if(dynamic_cast(this)) dynamic_cast(this)->removeUnsupportedProperties(properties); + else if(dynamic_cast(this)) + dynamic_cast(this)->removeUnsupportedProperties(properties); else tag()->removeUnsupportedProperties(properties); } @@ -219,6 +224,8 @@ PropertyMap File::setProperties(const PropertyMap &properties) return dynamic_cast(this)->setProperties(properties); else if(dynamic_cast(this)) return dynamic_cast(this)->setProperties(properties); + else if(dynamic_cast(this)) + return dynamic_cast(this)->setProperties(properties); else return tag()->setProperties(properties); }