diff --git a/Frameworks/TagLib/TagLib.xcodeproj/project.pbxproj b/Frameworks/TagLib/TagLib.xcodeproj/project.pbxproj index bec24abf4..a78bde3e7 100644 --- a/Frameworks/TagLib/TagLib.xcodeproj/project.pbxproj +++ b/Frameworks/TagLib/TagLib.xcodeproj/project.pbxproj @@ -199,6 +199,18 @@ 176608460F50A49000FD5752 /* mp4udtabox.h in Headers */ = {isa = PBXBuildFile; fileRef = 176607FE0F50A49000FD5752 /* mp4udtabox.h */; }; 17F767190F4FE2B2008498A7 /* tlist.tcc in Headers */ = {isa = PBXBuildFile; fileRef = 174C79A60F4FD40B00E18B0F /* tlist.tcc */; settings = {ATTRIBUTES = (Public, ); }; }; 17F7671A0F4FE2B2008498A7 /* tmap.tcc in Headers */ = {isa = PBXBuildFile; fileRef = 174C79A80F4FD40B00E18B0F /* tmap.tcc */; settings = {ATTRIBUTES = (Public, ); }; }; + 83BE026717FD6CF300973169 /* apefile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BE026317FD6CF300973169 /* apefile.cpp */; }; + 83BE026817FD6CF300973169 /* apefile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE026417FD6CF300973169 /* apefile.h */; }; + 83BE026917FD6CF300973169 /* apeproperties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BE026517FD6CF300973169 /* apeproperties.cpp */; }; + 83BE026A17FD6CF300973169 /* apeproperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE026617FD6CF300973169 /* apeproperties.h */; }; + 83BE027417FD716F00973169 /* asfattribute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BE026C17FD716F00973169 /* asfattribute.cpp */; }; + 83BE027517FD716F00973169 /* asfattribute.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE026D17FD716F00973169 /* asfattribute.h */; }; + 83BE027617FD716F00973169 /* asffile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BE026E17FD716F00973169 /* asffile.cpp */; }; + 83BE027717FD716F00973169 /* asffile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE026F17FD716F00973169 /* asffile.h */; }; + 83BE027817FD716F00973169 /* asfproperties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BE027017FD716F00973169 /* asfproperties.cpp */; }; + 83BE027917FD716F00973169 /* asfproperties.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE027117FD716F00973169 /* asfproperties.h */; }; + 83BE027A17FD716F00973169 /* asftag.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BE027217FD716F00973169 /* asftag.cpp */; }; + 83BE027B17FD716F00973169 /* asftag.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE027317FD716F00973169 /* asftag.h */; }; 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; /* End PBXBuildFile section */ @@ -396,6 +408,18 @@ 176607FC0F50A49000FD5752 /* mp4trakbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mp4trakbox.h; sourceTree = ""; }; 176607FD0F50A49000FD5752 /* mp4udtabox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mp4udtabox.cpp; sourceTree = ""; }; 176607FE0F50A49000FD5752 /* mp4udtabox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mp4udtabox.h; sourceTree = ""; }; + 83BE026317FD6CF300973169 /* apefile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = apefile.cpp; sourceTree = ""; }; + 83BE026417FD6CF300973169 /* apefile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apefile.h; sourceTree = ""; }; + 83BE026517FD6CF300973169 /* apeproperties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = apeproperties.cpp; sourceTree = ""; }; + 83BE026617FD6CF300973169 /* apeproperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apeproperties.h; sourceTree = ""; }; + 83BE026C17FD716F00973169 /* asfattribute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = asfattribute.cpp; sourceTree = ""; }; + 83BE026D17FD716F00973169 /* asfattribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asfattribute.h; sourceTree = ""; }; + 83BE026E17FD716F00973169 /* asffile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = asffile.cpp; sourceTree = ""; }; + 83BE026F17FD716F00973169 /* asffile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asffile.h; sourceTree = ""; }; + 83BE027017FD716F00973169 /* asfproperties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = asfproperties.cpp; sourceTree = ""; }; + 83BE027117FD716F00973169 /* asfproperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asfproperties.h; sourceTree = ""; }; + 83BE027217FD716F00973169 /* asftag.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = asftag.cpp; sourceTree = ""; }; + 83BE027317FD716F00973169 /* asftag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asftag.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; }; /* End PBXFileReference section */ @@ -467,6 +491,7 @@ 174C79340F4FD40B00E18B0F /* taglib */ = { isa = PBXGroup; children = ( + 83BE026B17FD716F00973169 /* asf */, 174C79350F4FD40B00E18B0F /* ape */, 174C793D0F4FD40B00E18B0F /* audioproperties.cpp */, 174C793E0F4FD40B00E18B0F /* audioproperties.h */, @@ -494,6 +519,10 @@ 174C79350F4FD40B00E18B0F /* ape */ = { isa = PBXGroup; children = ( + 83BE026317FD6CF300973169 /* apefile.cpp */, + 83BE026417FD6CF300973169 /* apefile.h */, + 83BE026517FD6CF300973169 /* apeproperties.cpp */, + 83BE026617FD6CF300973169 /* apeproperties.h */, 174C79360F4FD40B00E18B0F /* ape-tag-format.txt */, 174C79370F4FD40B00E18B0F /* apefooter.cpp */, 174C79380F4FD40B00E18B0F /* apefooter.h */, @@ -782,6 +811,21 @@ path = m4a; sourceTree = ""; }; + 83BE026B17FD716F00973169 /* asf */ = { + isa = PBXGroup; + children = ( + 83BE026C17FD716F00973169 /* asfattribute.cpp */, + 83BE026D17FD716F00973169 /* asfattribute.h */, + 83BE026E17FD716F00973169 /* asffile.cpp */, + 83BE026F17FD716F00973169 /* asffile.h */, + 83BE027017FD716F00973169 /* asfproperties.cpp */, + 83BE027117FD716F00973169 /* asfproperties.h */, + 83BE027217FD716F00973169 /* asftag.cpp */, + 83BE027317FD716F00973169 /* asftag.h */, + ); + path = asf; + sourceTree = ""; + }; 8E75700C09F318D70080F1EE /* Source */ = { isa = PBXGroup; children = ( @@ -804,6 +848,7 @@ 174C79C00F4FD40B00E18B0F /* apetag.h in Headers */, 174C79C20F4FD40B00E18B0F /* audioproperties.h in Headers */, 174C79C40F4FD40B00E18B0F /* fileref.h in Headers */, + 83BE027B17FD716F00973169 /* asftag.h in Headers */, 174C79C60F4FD40B00E18B0F /* flacfile.h in Headers */, 174C79C80F4FD40B00E18B0F /* flacproperties.h in Headers */, 174C79CA0F4FD40B00E18B0F /* mpcfile.h in Headers */, @@ -818,6 +863,7 @@ 174C79DC0F4FD40B00E18B0F /* uniquefileidentifierframe.h in Headers */, 174C79DE0F4FD40B00E18B0F /* unknownframe.h in Headers */, 174C79E00F4FD40B00E18B0F /* unsynchronizedlyricsframe.h in Headers */, + 83BE027917FD716F00973169 /* asfproperties.h in Headers */, 174C79E20F4FD40B00E18B0F /* urllinkframe.h in Headers */, 174C79E80F4FD40B00E18B0F /* id3v2extendedheader.h in Headers */, 174C79EA0F4FD40B00E18B0F /* id3v2footer.h in Headers */, @@ -832,12 +878,14 @@ 174C79FC0F4FD40B00E18B0F /* xingheader.h in Headers */, 174C79FE0F4FD40B00E18B0F /* oggflacfile.h in Headers */, 174C7A000F4FD40B00E18B0F /* oggfile.h in Headers */, + 83BE026A17FD6CF300973169 /* apeproperties.h in Headers */, 174C7A020F4FD40B00E18B0F /* oggpage.h in Headers */, 174C7A040F4FD40B00E18B0F /* oggpageheader.h in Headers */, 174C7A060F4FD40B00E18B0F /* speexfile.h in Headers */, 174C7A080F4FD40B00E18B0F /* speexproperties.h in Headers */, 174C7A0A0F4FD40B00E18B0F /* vorbisfile.h in Headers */, 174C7A0C0F4FD40B00E18B0F /* vorbisproperties.h in Headers */, + 83BE027717FD716F00973169 /* asffile.h in Headers */, 174C7A0E0F4FD40B00E18B0F /* xiphcomment.h in Headers */, 174C7A100F4FD40B00E18B0F /* tag.h in Headers */, 174C7A120F4FD40B00E18B0F /* taglib_export.h in Headers */, @@ -847,6 +895,7 @@ 174C7A190F4FD40B00E18B0F /* tbytevectorlist.h in Headers */, 174C7A1B0F4FD40B00E18B0F /* tdebug.h in Headers */, 174C7A1D0F4FD40B00E18B0F /* tfile.h in Headers */, + 83BE026817FD6CF300973169 /* apefile.h in Headers */, 174C7A1E0F4FD40B00E18B0F /* tlist.h in Headers */, 174C7A200F4FD40B00E18B0F /* tmap.h in Headers */, 174C7A230F4FD40B00E18B0F /* tstring.h in Headers */, @@ -870,6 +919,7 @@ 176608120F50A49000FD5752 /* itunesgrpbox.h in Headers */, 176608140F50A49000FD5752 /* itunesnambox.h in Headers */, 176608160F50A49000FD5752 /* itunestmpobox.h in Headers */, + 83BE027517FD716F00973169 /* asfattribute.h in Headers */, 176608180F50A49000FD5752 /* itunestrknbox.h in Headers */, 1766081A0F50A49000FD5752 /* ituneswrtbox.h in Headers */, 1766081C0F50A49000FD5752 /* mp4audioproperties.h in Headers */, @@ -976,6 +1026,7 @@ 174C79C90F4FD40B00E18B0F /* mpcfile.cpp in Sources */, 174C79CB0F4FD40B00E18B0F /* mpcproperties.cpp in Sources */, 174C79CD0F4FD40B00E18B0F /* id3v1genres.cpp in Sources */, + 83BE026717FD6CF300973169 /* apefile.cpp in Sources */, 174C79CF0F4FD40B00E18B0F /* id3v1tag.cpp in Sources */, 174C79D10F4FD40B00E18B0F /* attachedpictureframe.cpp in Sources */, 174C79D30F4FD40B00E18B0F /* commentsframe.cpp in Sources */, @@ -983,6 +1034,7 @@ 174C79D70F4FD40B00E18B0F /* relativevolumeframe.cpp in Sources */, 174C79D90F4FD40B00E18B0F /* textidentificationframe.cpp in Sources */, 174C79DB0F4FD40B00E18B0F /* uniquefileidentifierframe.cpp in Sources */, + 83BE027617FD716F00973169 /* asffile.cpp in Sources */, 174C79DD0F4FD40B00E18B0F /* unknownframe.cpp in Sources */, 174C79DF0F4FD40B00E18B0F /* unsynchronizedlyricsframe.cpp in Sources */, 174C79E10F4FD40B00E18B0F /* urllinkframe.cpp in Sources */, @@ -999,6 +1051,7 @@ 174C79FB0F4FD40B00E18B0F /* xingheader.cpp in Sources */, 174C79FD0F4FD40B00E18B0F /* oggflacfile.cpp in Sources */, 174C79FF0F4FD40B00E18B0F /* oggfile.cpp in Sources */, + 83BE026917FD6CF300973169 /* apeproperties.cpp in Sources */, 174C7A010F4FD40B00E18B0F /* oggpage.cpp in Sources */, 174C7A030F4FD40B00E18B0F /* oggpageheader.cpp in Sources */, 174C7A050F4FD40B00E18B0F /* speexfile.cpp in Sources */, @@ -1028,6 +1081,7 @@ 1766080B0F50A49000FD5752 /* itunesdaybox.cpp in Sources */, 1766080D0F50A49000FD5752 /* itunesdiskbox.cpp in Sources */, 1766080F0F50A49000FD5752 /* itunesgenbox.cpp in Sources */, + 83BE027817FD716F00973169 /* asfproperties.cpp in Sources */, 176608110F50A49000FD5752 /* itunesgrpbox.cpp in Sources */, 176608130F50A49000FD5752 /* itunesnambox.cpp in Sources */, 176608150F50A49000FD5752 /* itunestmpobox.cpp in Sources */, @@ -1042,11 +1096,13 @@ 176608270F50A49000FD5752 /* mp4isobox.cpp in Sources */, 176608290F50A49000FD5752 /* mp4isofullbox.cpp in Sources */, 1766082B0F50A49000FD5752 /* mp4itunestag.cpp in Sources */, + 83BE027A17FD716F00973169 /* asftag.cpp in Sources */, 1766082D0F50A49000FD5752 /* mp4mdiabox.cpp in Sources */, 1766082F0F50A49000FD5752 /* mp4metabox.cpp in Sources */, 176608310F50A49000FD5752 /* mp4minfbox.cpp in Sources */, 176608330F50A49000FD5752 /* mp4moovbox.cpp in Sources */, 176608350F50A49000FD5752 /* mp4mvhdbox.cpp in Sources */, + 83BE027417FD716F00973169 /* asfattribute.cpp in Sources */, 176608370F50A49000FD5752 /* mp4propsproxy.cpp in Sources */, 176608390F50A49000FD5752 /* mp4sampleentry.cpp in Sources */, 1766083B0F50A49000FD5752 /* mp4skipbox.cpp in Sources */, diff --git a/Frameworks/TagLib/taglib/taglib/ape/apefile.cpp b/Frameworks/TagLib/taglib/taglib/ape/apefile.cpp new file mode 100644 index 000000000..63d03ae13 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/ape/apefile.cpp @@ -0,0 +1,270 @@ +/*************************************************************************** + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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 "apefile.h" +#include "id3v1tag.h" + +#include "apetag.h" +#include "apefooter.h" + +using namespace TagLib; + +namespace +{ + enum { APEIndex, ID3v1Index }; +} + +class APE::File::FilePrivate +{ +public: + FilePrivate() : + APELocation(-1), + APESize(0), + ID3v1Location(-1), + properties(0), + hasAPE(false), + hasID3v1(false) {} + + ~FilePrivate() + { + delete properties; + } + + long APELocation; + uint APESize; + + long ID3v1Location; + + TagUnion tag; + + Properties *properties; + + // These indicate whether the file *on disk* has these tags, not if + // this data structure does. This is used in computing offsets. + + bool hasAPE; + bool hasID3v1; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +APE::File::File(FileName file, bool readProperties, + Properties::ReadStyle propertiesStyle) : TagLib::File(file) +{ + d = new FilePrivate; + read(readProperties, propertiesStyle); +} + +APE::File::~File() +{ + delete d; +} + +TagLib::Tag *APE::File::tag() const +{ + return &d->tag; +} + +APE::Properties *APE::File::audioProperties() const +{ + return d->properties; +} + +bool APE::File::save() +{ + if(readOnly()) { + debug("APE::File::save() -- File is read only."); + return false; + } + + // Update ID3v1 tag + + if(ID3v1Tag()) { + if(d->hasID3v1) { + seek(d->ID3v1Location); + writeBlock(ID3v1Tag()->render()); + } + else { + seek(0, End); + d->ID3v1Location = tell(); + writeBlock(ID3v1Tag()->render()); + d->hasID3v1 = true; + } + } + else { + if(d->hasID3v1) { + removeBlock(d->ID3v1Location, 128); + d->hasID3v1 = false; + if(d->hasAPE) { + if(d->APELocation > d->ID3v1Location) + d->APELocation -= 128; + } + } + } + + // Update APE tag + + if(APETag()) { + if(d->hasAPE) + insert(APETag()->render(), d->APELocation, d->APESize); + else { + if(d->hasID3v1) { + insert(APETag()->render(), d->ID3v1Location, 0); + d->APESize = APETag()->footer()->completeTagSize(); + d->hasAPE = true; + d->APELocation = d->ID3v1Location; + d->ID3v1Location += d->APESize; + } + else { + seek(0, End); + d->APELocation = tell(); + writeBlock(APETag()->render()); + d->APESize = APETag()->footer()->completeTagSize(); + d->hasAPE = true; + } + } + } + else { + if(d->hasAPE) { + removeBlock(d->APELocation, d->APESize); + d->hasAPE = false; + if(d->hasID3v1) { + if(d->ID3v1Location > d->APELocation) { + d->ID3v1Location -= d->APESize; + } + } + } + } + + return true; +} + +ID3v1::Tag *APE::File::ID3v1Tag(bool create) +{ + return d->tag.access(ID3v1Index, create); +} + +APE::Tag *APE::File::APETag(bool create) +{ + return d->tag.access(APEIndex, create); +} + +void APE::File::strip(int tags) +{ + if(tags & ID3v1) { + d->tag.set(ID3v1Index, 0); + APETag(true); + } + + if(tags & APE) { + d->tag.set(APEIndex, 0); + + if(!ID3v1Tag()) + APETag(true); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) +{ + // Look for an ID3v1 tag + + d->ID3v1Location = findID3v1(); + + if(d->ID3v1Location >= 0) { + d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); + d->hasID3v1 = true; + } + + // Look for an APE tag + + d->APELocation = findAPE(); + + if(d->APELocation >= 0) { + d->tag.set(APEIndex, new APE::Tag(this, d->APELocation)); + d->APESize = APETag()->footer()->completeTagSize(); + d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; + d->hasAPE = true; + } + + if(!d->hasID3v1) + APETag(true); + + // Look for APE audio properties + + if(readProperties) { + d->properties = new Properties(this); + } +} + +long APE::File::findAPE() +{ + if(!isValid()) + return -1; + + if(d->hasID3v1) + seek(-160, End); + else + seek(-32, End); + + long p = tell(); + + if(readBlock(8) == APE::Tag::fileIdentifier()) + return p; + + return -1; +} + +long APE::File::findID3v1() +{ + if(!isValid()) + return -1; + + seek(-128, End); + long p = tell(); + + if(readBlock(3) == ID3v1::Tag::fileIdentifier()) + return p; + + return -1; +} diff --git a/Frameworks/TagLib/taglib/taglib/ape/apefile.h b/Frameworks/TagLib/taglib/taglib/ape/apefile.h new file mode 100644 index 000000000..3f641b7d9 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/ape/apefile.h @@ -0,0 +1,171 @@ +/*************************************************************************** + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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_APEFILE_H +#define TAGLIB_APEFILE_H + +#include "tfile.h" +#include "taglib_export.h" +#include "apeproperties.h" + +namespace TagLib { + + class Tag; + + namespace ID3v1 { class Tag; } + namespace APE { class Tag; } + + //! An implementation of APE metadata + + /*! + * This is implementation of APE metadata. + * + * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream + * properties from the file. + */ + + namespace APE { + + //! An implementation of TagLib::File with APE specific methods + + /*! + * This implements and provides an interface APE WavPack files to the + * 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 files. + */ + + 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 ID3v1 tags. + ID3v1 = 0x0001, + //! Matches APE tags. + APE = 0x0002, + //! Matches all tag types. + AllTags = 0xffff + }; + + /*! + * Contructs an WavPack file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. + */ + File(FileName file, 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, an ID3v1 tag + * or a combination of the two. + */ + virtual TagLib::Tag *tag() const; + + /*! + * 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. + * + * \note According to the official Monkey's Audio SDK, an APE file + * can only have either ID3V1 or APE tags, so a parameter is used here. + */ + virtual bool save(); + + /*! + * Returns a pointer to the ID3v1 tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid ID3v1 tag. If \a create is true it will create + * an ID3v1 tag if one does not exist. If there is already an APE tag, the + * new ID3v1 tag will be placed after it. + * + * \note The Tag is still owned by the APE::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + ID3v1::Tag *ID3v1Tag(bool create = false); + + /*! + * Returns a pointer to the APE tag of the file. + * + * If \a create is false (the default) this will return a null pointer + * if there is no valid APE tag. If \a create is true it will create + * a APE tag if one does not exist. + * + * \note The Tag is still owned by the APE::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + 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); + + private: + File(const File &); + File &operator=(const File &); + + void read(bool readProperties, Properties::ReadStyle propertiesStyle); + void scan(); + long findID3v1(); + long findAPE(); + + class FilePrivate; + FilePrivate *d; + }; + } +} + +#endif diff --git a/Frameworks/TagLib/taglib/taglib/ape/apeproperties.cpp b/Frameworks/TagLib/taglib/taglib/ape/apeproperties.cpp new file mode 100644 index 000000000..7ee55bc7b --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/ape/apeproperties.cpp @@ -0,0 +1,224 @@ +/*************************************************************************** + copyright : (C) 2010 by Alex Novichkov + email : novichko@atnet.ru + + copyright : (C) 2006 by Lukáš Lalinský + email : lalinsky@gmail.com + (original WavPack 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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 "id3v2tag.h" +#include "apeproperties.h" +#include "apefile.h" + +using namespace TagLib; + +class APE::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate(File *file, long streamLength) : + length(0), + bitrate(0), + sampleRate(0), + channels(0), + version(0), + bitsPerSample(0), + file(file), + streamLength(streamLength) {} + + long streamLength; + int length; + int bitrate; + int sampleRate; + int channels; + int version; + int bitsPerSample; + File *file; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +APE::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) +{ + d = new PropertiesPrivate(file, file->length()); + read(); +} + +APE::Properties::~Properties() +{ + delete d; +} + +int APE::Properties::length() const +{ + return d->length; +} + +int APE::Properties::bitrate() const +{ + return d->bitrate; +} + +int APE::Properties::sampleRate() const +{ + return d->sampleRate; +} + +int APE::Properties::channels() const +{ + return d->channels; +} + +int APE::Properties::version() const +{ + return d->version; +} + +int APE::Properties::bitsPerSample() const +{ + return d->bitsPerSample; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + + +void APE::Properties::read() +{ + // First we are searching the descriptor + long offset = findDescriptor(); + if(offset < 0) + return; + + // Then we read the header common for all versions of APE + d->file->seek(offset); + ByteVector commonHeader=d->file->readBlock(6); + if(!commonHeader.startsWith("MAC ")) + return; + d->version = commonHeader.mid(4).toUInt(false); + + if(d->version >= 3980) { + analyzeCurrent(); + } + else { + analyzeOld(); + } +} + +long APE::Properties::findDescriptor() +{ + long ID3v2Location = findID3v2(); + long ID3v2OriginalSize = 0; + bool hasID3v2 = false; + if(ID3v2Location >= 0) { + ID3v2::Tag tag(d->file, ID3v2Location, 0); + ID3v2OriginalSize = tag.header()->completeTagSize(); + if(tag.header()->tagSize() > 0) + hasID3v2 = true; + } + + long offset = 0; + if(hasID3v2) + offset = d->file->find("MAC ", ID3v2Location + ID3v2OriginalSize); + else + offset = d->file->find("MAC "); + + if(offset < 0) { + debug("APE::Properties::findDescriptor() -- APE descriptor not found"); + return -1; + } + + return offset; +} + +long APE::Properties::findID3v2() +{ + if(!d->file->isValid()) + return -1; + + d->file->seek(0); + + if(d->file->readBlock(3) == ID3v2::Header::fileIdentifier()) + return 0; + + return -1; +} + +void APE::Properties::analyzeCurrent() +{ + // Read the descriptor + d->file->seek(2, File::Current); + ByteVector descriptor = d->file->readBlock(44); + uint descriptorBytes = descriptor.mid(0,4).toUInt(false); + + if ((descriptorBytes - 52) > 0) + d->file->seek(descriptorBytes - 52, File::Current); + + // Read the header + ByteVector header = d->file->readBlock(24); + + // Get the APE info + d->channels = header.mid(18, 2).toShort(false); + d->sampleRate = header.mid(20, 4).toUInt(false); + d->bitsPerSample = header.mid(16, 2).toShort(false); + //d->compressionLevel = + + uint totalFrames = header.mid(12, 4).toUInt(false); + uint blocksPerFrame = header.mid(4, 4).toUInt(false); + uint finalFrameBlocks = header.mid(8, 4).toUInt(false); + uint totalBlocks = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0; + d->length = totalBlocks / d->sampleRate; + d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; +} + +void APE::Properties::analyzeOld() +{ + ByteVector header = d->file->readBlock(26); + uint totalFrames = header.mid(18, 4).toUInt(false); + + // Fail on 0 length APE files (catches non-finalized APE files) + if(totalFrames == 0) + return; + + short compressionLevel = header.mid(0, 2).toShort(false); + uint blocksPerFrame; + if(d->version >= 3950) + blocksPerFrame = 73728 * 4; + else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000)) + blocksPerFrame = 73728; + else + blocksPerFrame = 9216; + d->channels = header.mid(4, 2).toShort(false); + d->sampleRate = header.mid(6, 4).toUInt(false); + uint finalFrameBlocks = header.mid(22, 4).toUInt(false); + uint totalBlocks = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0; + d->length = totalBlocks / d->sampleRate; + d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; +} + diff --git a/Frameworks/TagLib/taglib/taglib/ape/apeproperties.h b/Frameworks/TagLib/taglib/taglib/ape/apeproperties.h new file mode 100644 index 000000000..3fb020e36 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/ape/apeproperties.h @@ -0,0 +1,98 @@ +/*************************************************************************** + copyright : (C) 2010 by Alex Novichkov + email : novichko@atnet.ru + + copyright : (C) 2006 by Lukáš Lalinský + email : lalinsky@gmail.com + (original WavPack 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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_APEPROPERTIES_H +#define TAGLIB_APEPROPERTIES_H + +#include "taglib_export.h" +#include "audioproperties.h" + +namespace TagLib { + + namespace APE { + + class File; + + //! An implementation of audio property reading for APE + + /*! + * This reads the data from an APE stream found in the AudioProperties + * API. + */ + + class TAGLIB_EXPORT Properties : public AudioProperties + { + public: + /*! + * Create an instance of APE::Properties with the data read from the + * ByteVector \a data. + */ + Properties(File *f, ReadStyle style = Average); + + /*! + * Destroys this APE::Properties instance. + */ + virtual ~Properties(); + + // Reimplementations. + + virtual int length() const; + virtual int bitrate() const; + virtual int sampleRate() const; + virtual int channels() const; + + /*! + * Returns number of bits per sample. + */ + int bitsPerSample() const; + + /*! + * Returns APE version. + */ + int version() const; + + private: + Properties(const Properties &); + Properties &operator=(const Properties &); + + void read(); + + long findDescriptor(); + long findID3v2(); + + void analyzeCurrent(); + void analyzeOld(); + + class PropertiesPrivate; + PropertiesPrivate *d; + }; + } +} + +#endif diff --git a/Frameworks/TagLib/taglib/taglib/ape/apetag.h b/Frameworks/TagLib/taglib/taglib/ape/apetag.h index 492114ab5..934fd4772 100644 --- a/Frameworks/TagLib/taglib/taglib/ape/apetag.h +++ b/Frameworks/TagLib/taglib/taglib/ape/apetag.h @@ -66,7 +66,7 @@ namespace TagLib { * Create an APE tag and parse the data in \a file with APE footer at * \a tagOffset. */ - Tag(File *file, long footerLocation); + Tag(TagLib::File *file, long footerLocation); /*! * Destroys this Tag instance. diff --git a/Frameworks/TagLib/taglib/taglib/asf/asfattribute.cpp b/Frameworks/TagLib/taglib/taglib/asf/asfattribute.cpp new file mode 100644 index 000000000..809a08e6f --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/asf/asfattribute.cpp @@ -0,0 +1,338 @@ +/************************************************************************** + copyright : (C) 2005-2007 by Lukáš Lalinský + email : lalinsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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/ * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "asfattribute.h" +#include "asffile.h" + +using namespace TagLib; + +class ASF::Attribute::AttributePrivate : public RefCounter +{ +public: + AttributePrivate() + : stream(0), + language(0) {} + AttributeTypes type; + String stringValue; + ByteVector byteVectorValue; + union { + unsigned int intValue; + unsigned short shortValue; + unsigned long long longLongValue; + bool boolValue; + }; + int stream; + int language; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +ASF::Attribute::Attribute() +{ + d = new AttributePrivate; + d->type = UnicodeType; +} + +ASF::Attribute::Attribute(const ASF::Attribute &other) + : d(other.d) +{ + d->ref(); +} + +ASF::Attribute & +ASF::Attribute::operator=(const ASF::Attribute &other) +{ + if(d->deref()) + delete d; + d = other.d; + d->ref(); + return *this; +} + +ASF::Attribute::~Attribute() +{ + if(d->deref()) + delete d; +} + +ASF::Attribute::Attribute(const String &value) +{ + d = new AttributePrivate; + d->type = UnicodeType; + d->stringValue = value; +} + +ASF::Attribute::Attribute(const ByteVector &value) +{ + d = new AttributePrivate; + d->type = BytesType; + d->byteVectorValue = value; +} + +ASF::Attribute::Attribute(unsigned int value) +{ + d = new AttributePrivate; + d->type = DWordType; + d->intValue = value; +} + +ASF::Attribute::Attribute(unsigned long long value) +{ + d = new AttributePrivate; + d->type = QWordType; + d->longLongValue = value; +} + +ASF::Attribute::Attribute(unsigned short value) +{ + d = new AttributePrivate; + d->type = WordType; + d->shortValue = value; +} + +ASF::Attribute::Attribute(bool value) +{ + d = new AttributePrivate; + d->type = BoolType; + d->boolValue = value; +} + +ASF::Attribute::AttributeTypes +ASF::Attribute::type() const +{ + return d->type; +} + +String +ASF::Attribute::toString() const +{ + return d->stringValue; +} + +ByteVector +ASF::Attribute::toByteVector() const +{ + return d->byteVectorValue; +} + +unsigned short +ASF::Attribute::toBool() const +{ + return d->shortValue; +} + +unsigned short +ASF::Attribute::toUShort() const +{ + return d->shortValue; +} + +unsigned int +ASF::Attribute::toUInt() const +{ + return d->intValue; +} + +unsigned long long +ASF::Attribute::toULongLong() const +{ + return d->longLongValue; +} + +String +ASF::Attribute::parse(ASF::File &f, int kind) +{ + int size, nameLength; + String name; + + // extended content descriptor + if(kind == 0) { + nameLength = f.readWORD(); + name = f.readString(nameLength); + d->type = ASF::Attribute::AttributeTypes(f.readWORD()); + size = f.readWORD(); + } + // metadata & metadata library + else { + int temp = f.readWORD(); + // metadata library + if(kind == 2) { + d->language = temp; + } + d->stream = f.readWORD(); + nameLength = f.readWORD(); + d->type = ASF::Attribute::AttributeTypes(f.readWORD()); + size = f.readDWORD(); + name = f.readString(nameLength); + } + + if(kind != 2 && size > 65535) { + debug("ASF::Attribute::parse() -- Value larger than 64kB"); + } + + switch(d->type) { + case WordType: + d->shortValue = f.readWORD(); + break; + + case BoolType: + if(kind == 0) { + d->boolValue = f.readDWORD() == 1; + } + else { + d->boolValue = f.readWORD() == 1; + } + break; + + case DWordType: + d->intValue = f.readDWORD(); + break; + + case QWordType: + d->longLongValue = f.readQWORD(); + break; + + case UnicodeType: + d->stringValue = f.readString(size); + break; + + case BytesType: + case GuidType: + d->byteVectorValue = f.readBlock(size); + break; + } + + return name; +} + +int +ASF::Attribute::dataSize() const +{ + switch (d->type) { + case WordType: + return 2; + case BoolType: + return 4; + case DWordType: + return 4; + case QWordType: + return 5; + case UnicodeType: + return d->stringValue.size() * 2 + 2; + case BytesType: + case GuidType: + return d->byteVectorValue.size(); + } + return 0; +} + +ByteVector +ASF::Attribute::render(const String &name, int kind) const +{ + ByteVector data; + + switch (d->type) { + case WordType: + data.append(ByteVector::fromShort(d->shortValue, false)); + break; + + case BoolType: + if(kind == 0) { + data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false)); + } + else { + data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false)); + } + break; + + case DWordType: + data.append(ByteVector::fromUInt(d->intValue, false)); + break; + + case QWordType: + data.append(ByteVector::fromLongLong(d->longLongValue, false)); + break; + + case UnicodeType: + data.append(File::renderString(d->stringValue)); + break; + + case BytesType: + case GuidType: + data.append(d->byteVectorValue); + break; + } + + if(kind == 0) { + data = File::renderString(name, true) + + ByteVector::fromShort((int)d->type, false) + + ByteVector::fromShort(data.size(), false) + + data; + } + else { + ByteVector nameData = File::renderString(name); + data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) + + ByteVector::fromShort(d->stream, false) + + ByteVector::fromShort(nameData.size(), false) + + ByteVector::fromShort((int)d->type, false) + + ByteVector::fromUInt(data.size(), false) + + nameData + + data; + } + + return data; +} + +int +ASF::Attribute::language() const +{ + return d->language; +} + +void +ASF::Attribute::setLanguage(int value) +{ + d->language = value; +} + +int +ASF::Attribute::stream() const +{ + return d->stream; +} + +void +ASF::Attribute::setStream(int value) +{ + d->stream = value; +} diff --git a/Frameworks/TagLib/taglib/taglib/asf/asfattribute.h b/Frameworks/TagLib/taglib/taglib/asf/asfattribute.h new file mode 100644 index 000000000..975238949 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/asf/asfattribute.h @@ -0,0 +1,184 @@ +/************************************************************************** + copyright : (C) 2005-2007 by Lukáš Lalinský + email : lalinsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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_ASFATTRIBUTE_H +#define TAGLIB_ASFATTRIBUTE_H + +#include "tstring.h" +#include "tbytevector.h" +#include "taglib_export.h" + +namespace TagLib +{ + + namespace ASF + { + + class File; + + class TAGLIB_EXPORT Attribute + { + public: + + /*! + * Enum of types an Attribute can have. + */ + enum AttributeTypes { + UnicodeType = 0, + BytesType = 1, + BoolType = 2, + DWordType = 3, + QWordType = 4, + WordType = 5, + GuidType = 6 + }; + + /*! + * Constructs an empty attribute. + */ + Attribute(); + + /*! + * Constructs an attribute with \a key and a UnicodeType \a value. + */ + Attribute(const String &value); + + /*! + * Constructs an attribute with \a key and a BytesType \a value. + */ + Attribute(const ByteVector &value); + + /*! + * Constructs an attribute with \a key and a DWordType \a value. + */ + Attribute(unsigned int value); + + /*! + * Constructs an attribute with \a key and a QWordType \a value. + */ + Attribute(unsigned long long value); + + /*! + * Constructs an attribute with \a key and a WordType \a value. + */ + Attribute(unsigned short value); + + /*! + * Constructs an attribute with \a key and a BoolType \a value. + */ + Attribute(bool value); + + /*! + * Construct an attribute as a copy of \a other. + */ + Attribute(const Attribute &item); + + /*! + * Copies the contents of \a other into this item. + */ + ASF::Attribute &operator=(const Attribute &other); + + /*! + * Destroys the attribute. + */ + virtual ~Attribute(); + + /*! + * Returns type of the value. + */ + AttributeTypes type() const; + + /*! + * Returns the BoolType \a value. + */ + unsigned short toBool() const; + + /*! + * Returns the WordType \a value. + */ + unsigned short toUShort() const; + + /*! + * Returns the DWordType \a value. + */ + unsigned int toUInt() const; + + /*! + * Returns the QWordType \a value. + */ + unsigned long long toULongLong() const; + + /*! + * Returns the UnicodeType \a value. + */ + String toString() const; + + /*! + * Returns the BytesType \a value. + */ + ByteVector toByteVector() const; + + /*! + * Returns the language number, or 0 is no stream number was set. + */ + int language() const; + + /*! + * Sets the language number. + */ + void setLanguage(int value); + + /*! + * Returns the stream number, or 0 is no stream number was set. + */ + int stream() const; + + /*! + * Sets the stream number. + */ + void setStream(int value); + +#ifndef DO_NOT_DOCUMENT + /* THIS IS PRIVATE, DON'T TOUCH IT! */ + String parse(ASF::File &file, int kind = 0); +#endif + + //! Returns the size of the stored data + int dataSize() const; + + private: + friend class File; + + ByteVector render(const String &name, int kind = 0) const; + + class AttributePrivate; + AttributePrivate *d; + }; + + } + +} + +#endif diff --git a/Frameworks/TagLib/taglib/taglib/asf/asffile.cpp b/Frameworks/TagLib/taglib/taglib/asf/asffile.cpp new file mode 100644 index 000000000..512940cd8 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/asf/asffile.cpp @@ -0,0 +1,559 @@ +/************************************************************************** + copyright : (C) 2005-2007 by Lukáš Lalinský + email : lalinsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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/ * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include "asffile.h" +#include "asftag.h" +#include "asfproperties.h" + +using namespace TagLib; + +class ASF::File::FilePrivate +{ +public: + FilePrivate(): + size(0), + tag(0), + properties(0), + contentDescriptionObject(0), + extendedContentDescriptionObject(0), + headerExtensionObject(0), + metadataObject(0), + metadataLibraryObject(0) {} + unsigned long long size; + ASF::Tag *tag; + ASF::Properties *properties; + List objects; + ASF::File::ContentDescriptionObject *contentDescriptionObject; + ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject; + ASF::File::HeaderExtensionObject *headerExtensionObject; + ASF::File::MetadataObject *metadataObject; + ASF::File::MetadataLibraryObject *metadataLibraryObject; +}; + +static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); +static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16); +static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16); +static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); +static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16); +static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16); +static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16); +static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16); + +class ASF::File::BaseObject +{ +public: + ByteVector data; + virtual ~BaseObject() {} + virtual ByteVector guid() = 0; + virtual void parse(ASF::File *file, unsigned int size); + virtual ByteVector render(ASF::File *file); +}; + +class ASF::File::UnknownObject : public ASF::File::BaseObject +{ + ByteVector myGuid; +public: + UnknownObject(const ByteVector &guid); + ByteVector guid(); +}; + +class ASF::File::FilePropertiesObject : public ASF::File::BaseObject +{ +public: + ByteVector guid(); + void parse(ASF::File *file, uint size); +}; + +class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject +{ +public: + ByteVector guid(); + void parse(ASF::File *file, uint size); +}; + +class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject +{ +public: + ByteVector guid(); + void parse(ASF::File *file, uint size); + ByteVector render(ASF::File *file); +}; + +class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject +{ +public: + ByteVectorList attributeData; + ByteVector guid(); + void parse(ASF::File *file, uint size); + ByteVector render(ASF::File *file); +}; + +class ASF::File::MetadataObject : public ASF::File::BaseObject +{ +public: + ByteVectorList attributeData; + ByteVector guid(); + void parse(ASF::File *file, uint size); + ByteVector render(ASF::File *file); +}; + +class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject +{ +public: + ByteVectorList attributeData; + ByteVector guid(); + void parse(ASF::File *file, uint size); + ByteVector render(ASF::File *file); +}; + +class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject +{ +public: + List objects; + ByteVector guid(); + void parse(ASF::File *file, uint size); + ByteVector render(ASF::File *file); +}; + +void +ASF::File::BaseObject::parse(ASF::File *file, unsigned int size) +{ + data = file->readBlock(size - 24); +} + +ByteVector +ASF::File::BaseObject::render(ASF::File * /*file*/) +{ + return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data; +} + +ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid) +{ +} + +ByteVector +ASF::File::UnknownObject::guid() +{ + return myGuid; +} + +ByteVector +ASF::File::FilePropertiesObject::guid() +{ + return filePropertiesGuid; +} + +void +ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size) +{ + BaseObject::parse(file, size); + file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L)); +} + +ByteVector +ASF::File::StreamPropertiesObject::guid() +{ + return streamPropertiesGuid; +} + +void +ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size) +{ + BaseObject::parse(file, size); + file->d->properties->setChannels(data.mid(56, 2).toShort(false)); + file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false)); + file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000); +} + +ByteVector +ASF::File::ContentDescriptionObject::guid() +{ + return contentDescriptionGuid; +} + +void +ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/) +{ + file->d->contentDescriptionObject = this; + int titleLength = file->readWORD(); + int artistLength = file->readWORD(); + int copyrightLength = file->readWORD(); + int commentLength = file->readWORD(); + int ratingLength = file->readWORD(); + file->d->tag->setTitle(file->readString(titleLength)); + file->d->tag->setArtist(file->readString(artistLength)); + file->d->tag->setCopyright(file->readString(copyrightLength)); + file->d->tag->setComment(file->readString(commentLength)); + file->d->tag->setRating(file->readString(ratingLength)); +} + +ByteVector +ASF::File::ContentDescriptionObject::render(ASF::File *file) +{ + ByteVector v1 = file->renderString(file->d->tag->title()); + ByteVector v2 = file->renderString(file->d->tag->artist()); + ByteVector v3 = file->renderString(file->d->tag->copyright()); + ByteVector v4 = file->renderString(file->d->tag->comment()); + ByteVector v5 = file->renderString(file->d->tag->rating()); + data.clear(); + data.append(ByteVector::fromShort(v1.size(), false)); + data.append(ByteVector::fromShort(v2.size(), false)); + data.append(ByteVector::fromShort(v3.size(), false)); + data.append(ByteVector::fromShort(v4.size(), false)); + data.append(ByteVector::fromShort(v5.size(), false)); + data.append(v1); + data.append(v2); + data.append(v3); + data.append(v4); + data.append(v5); + return BaseObject::render(file); +} + +ByteVector +ASF::File::ExtendedContentDescriptionObject::guid() +{ + return extendedContentDescriptionGuid; +} + +void +ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/) +{ + file->d->extendedContentDescriptionObject = this; + int count = file->readWORD(); + while(count--) { + ASF::Attribute attribute; + String name = attribute.parse(*file); + file->d->tag->addAttribute(name, attribute); + } +} + +ByteVector +ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file) +{ + data.clear(); + data.append(ByteVector::fromShort(attributeData.size(), false)); + data.append(attributeData.toByteVector(ByteVector::null)); + return BaseObject::render(file); +} + +ByteVector +ASF::File::MetadataObject::guid() +{ + return metadataGuid; +} + +void +ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/) +{ + file->d->metadataObject = this; + int count = file->readWORD(); + while(count--) { + ASF::Attribute attribute; + String name = attribute.parse(*file, 1); + file->d->tag->addAttribute(name, attribute); + } +} + +ByteVector +ASF::File::MetadataObject::render(ASF::File *file) +{ + data.clear(); + data.append(ByteVector::fromShort(attributeData.size(), false)); + data.append(attributeData.toByteVector(ByteVector::null)); + return BaseObject::render(file); +} + +ByteVector +ASF::File::MetadataLibraryObject::guid() +{ + return metadataLibraryGuid; +} + +void +ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/) +{ + file->d->metadataLibraryObject = this; + int count = file->readWORD(); + while(count--) { + ASF::Attribute attribute; + String name = attribute.parse(*file, 2); + file->d->tag->addAttribute(name, attribute); + } +} + +ByteVector +ASF::File::MetadataLibraryObject::render(ASF::File *file) +{ + data.clear(); + data.append(ByteVector::fromShort(attributeData.size(), false)); + data.append(attributeData.toByteVector(ByteVector::null)); + return BaseObject::render(file); +} + +ByteVector +ASF::File::HeaderExtensionObject::guid() +{ + return headerExtensionGuid; +} + +void +ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/) +{ + file->d->headerExtensionObject = this; + file->seek(18, File::Current); + long long dataSize = file->readDWORD(); + long long dataPos = 0; + while(dataPos < dataSize) { + ByteVector guid = file->readBlock(16); + long long size = file->readQWORD(); + BaseObject *obj; + if(guid == metadataGuid) { + obj = new MetadataObject(); + } + else if(guid == metadataLibraryGuid) { + obj = new MetadataLibraryObject(); + } + else { + obj = new UnknownObject(guid); + } + obj->parse(file, size); + objects.append(obj); + dataPos += size; + } +} + +ByteVector +ASF::File::HeaderExtensionObject::render(ASF::File *file) +{ + data.clear(); + for(unsigned int i = 0; i < objects.size(); i++) { + data.append(objects[i]->render(file)); + } + data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data; + return BaseObject::render(file); +} + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) + : TagLib::File(file) +{ + d = new FilePrivate; + read(readProperties, propertiesStyle); +} + +ASF::File::~File() +{ + for(unsigned int i = 0; i < d->objects.size(); i++) { + delete d->objects[i]; + } + if(d->tag) { + delete d->tag; + } + if(d->properties) { + delete d->properties; + } + delete d; +} + +ASF::Tag *ASF::File::tag() const +{ + return d->tag; +} + +ASF::Properties *ASF::File::audioProperties() const +{ + return d->properties; +} + +void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/) +{ + if(!isValid()) + return; + + ByteVector guid = readBlock(16); + if(guid != headerGuid) { + debug("ASF: Not an ASF file."); + return; + } + + d->tag = new ASF::Tag(); + d->properties = new ASF::Properties(); + + d->size = readQWORD(); + int numObjects = readDWORD(); + seek(2, Current); + + for(int i = 0; i < numObjects; i++) { + ByteVector guid = readBlock(16); + long size = (long)readQWORD(); + BaseObject *obj; + if(guid == filePropertiesGuid) { + obj = new FilePropertiesObject(); + } + else if(guid == streamPropertiesGuid) { + obj = new StreamPropertiesObject(); + } + else if(guid == contentDescriptionGuid) { + obj = new ContentDescriptionObject(); + } + else if(guid == extendedContentDescriptionGuid) { + obj = new ExtendedContentDescriptionObject(); + } + else if(guid == headerExtensionGuid) { + obj = new HeaderExtensionObject(); + } + else { + obj = new UnknownObject(guid); + } + obj->parse(this, size); + d->objects.append(obj); + } +} + +bool ASF::File::save() +{ + if(readOnly()) { + debug("ASF: File is read-only."); + return false; + } + + if(!d->contentDescriptionObject) { + d->contentDescriptionObject = new ContentDescriptionObject(); + d->objects.append(d->contentDescriptionObject); + } + if(!d->extendedContentDescriptionObject) { + d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject(); + d->objects.append(d->extendedContentDescriptionObject); + } + if(!d->headerExtensionObject) { + d->headerExtensionObject = new HeaderExtensionObject(); + d->objects.append(d->headerExtensionObject); + } + if(!d->metadataObject) { + d->metadataObject = new MetadataObject(); + d->headerExtensionObject->objects.append(d->metadataObject); + } + if(!d->metadataLibraryObject) { + d->metadataLibraryObject = new MetadataLibraryObject(); + d->headerExtensionObject->objects.append(d->metadataLibraryObject); + } + + ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin(); + for(; it != d->tag->attributeListMap().end(); it++) { + const String &name = it->first; + const AttributeList &attributes = it->second; + bool inExtendedContentDescriptionObject = false; + bool inMetadataObject = false; + for(unsigned int j = 0; j < attributes.size(); j++) { + const Attribute &attribute = attributes[j]; + bool largeValue = attribute.dataSize() > 65535; + if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) { + d->extendedContentDescriptionObject->attributeData.append(attribute.render(name)); + inExtendedContentDescriptionObject = true; + } + else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) { + d->metadataObject->attributeData.append(attribute.render(name, 1)); + inMetadataObject = true; + } + else { + d->metadataLibraryObject->attributeData.append(attribute.render(name, 2)); + } + } + } + + ByteVector data; + for(unsigned int i = 0; i < d->objects.size(); i++) { + data.append(d->objects[i]->render(this)); + } + data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data; + insert(data, 0, d->size); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// protected members +//////////////////////////////////////////////////////////////////////////////// + +int ASF::File::readBYTE() +{ + ByteVector v = readBlock(1); + return v[0]; +} + +int ASF::File::readWORD() +{ + ByteVector v = readBlock(2); + return v.toShort(false); +} + +unsigned int ASF::File::readDWORD() +{ + ByteVector v = readBlock(4); + return v.toUInt(false); +} + +long long ASF::File::readQWORD() +{ + ByteVector v = readBlock(8); + return v.toLongLong(false); +} + +String +ASF::File::readString(int length) +{ + ByteVector data = readBlock(length); + unsigned int size = data.size(); + while (size >= 2) { + if(data[size - 1] != '\0' || data[size - 2] != '\0') { + break; + } + size -= 2; + } + if(size != data.size()) { + data.resize(size); + } + return String(data, String::UTF16LE); +} + +ByteVector +ASF::File::renderString(const String &str, bool includeLength) +{ + ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false); + if(includeLength) { + data = ByteVector::fromShort(data.size(), false) + data; + } + return data; +} diff --git a/Frameworks/TagLib/taglib/taglib/asf/asffile.h b/Frameworks/TagLib/taglib/taglib/asf/asffile.h new file mode 100644 index 000000000..23a6d009a --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/asf/asffile.h @@ -0,0 +1,119 @@ +/************************************************************************** + copyright : (C) 2005-2007 by Lukáš Lalinský + email : lalinsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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_ASFFILE_H +#define TAGLIB_ASFFILE_H + +#include "tag.h" +#include "tfile.h" +#include "taglib_export.h" +#include "asfproperties.h" +#include "asftag.h" + +namespace TagLib { + + //! An implementation of ASF (WMA) metadata + namespace ASF { + + /*! + * This implements and provides an interface for ASF files to the + * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing + * the abstract TagLib::File API as well as providing some additional + * information specific to ASF files. + */ + class TAGLIB_EXPORT File : public TagLib::File + { + public: + + /*! + * Contructs an ASF file from \a file. If \a readProperties is true the + * file's audio properties will also be read using \a propertiesStyle. If + * false, \a propertiesStyle is ignored. + * + * \note In the current implementation, both \a readProperties and + * \a propertiesStyle are ignored. + */ + File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average); + + /*! + * Destroys this instance of the File. + */ + virtual ~File(); + + /*! + * Returns a pointer to the ASF tag of the file. + * + * ASF::Tag implements the tag interface, so this serves as the + * reimplementation of TagLib::File::tag(). + * + * \note The Tag is still owned by the ASF::File and should not be + * deleted by the user. It will be deleted when the file (object) is + * destroyed. + */ + virtual Tag *tag() const; + + /*! + * Returns the ASF audio properties for this file. + */ + virtual Properties *audioProperties() const; + + /*! + * Save the file. + * + * This returns true if the save was successful. + */ + virtual bool save(); + + private: + + int readBYTE(); + int readWORD(); + unsigned int readDWORD(); + long long readQWORD(); + static ByteVector renderString(const String &str, bool includeLength = false); + String readString(int len); + void read(bool readProperties, Properties::ReadStyle propertiesStyle); + + friend class Attribute; + + class BaseObject; + class UnknownObject; + class FilePropertiesObject; + class StreamPropertiesObject; + class ContentDescriptionObject; + class ExtendedContentDescriptionObject; + class HeaderExtensionObject; + class MetadataObject; + class MetadataLibraryObject; + + class FilePrivate; + FilePrivate *d; + }; + + } + +} + +#endif diff --git a/Frameworks/TagLib/taglib/taglib/asf/asfproperties.cpp b/Frameworks/TagLib/taglib/taglib/asf/asfproperties.cpp new file mode 100644 index 000000000..2d6776c18 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/asf/asfproperties.cpp @@ -0,0 +1,103 @@ +/************************************************************************** + copyright : (C) 2005-2007 by Lukáš Lalinský + email : lalinsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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/ * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "asfproperties.h" + +using namespace TagLib; + +class ASF::Properties::PropertiesPrivate +{ +public: + PropertiesPrivate(): length(0), bitrate(0), sampleRate(0), channels(0) {} + int length; + int bitrate; + int sampleRate; + int channels; +}; + +//////////////////////////////////////////////////////////////////////////////// +// public members +//////////////////////////////////////////////////////////////////////////////// + +ASF::Properties::Properties() : AudioProperties(AudioProperties::Average) +{ + d = new PropertiesPrivate; +} + +ASF::Properties::~Properties() +{ + if(d) + delete d; +} + +int ASF::Properties::length() const +{ + return d->length; +} + +int ASF::Properties::bitrate() const +{ + return d->bitrate; +} + +int ASF::Properties::sampleRate() const +{ + return d->sampleRate; +} + +int ASF::Properties::channels() const +{ + return d->channels; +} + +//////////////////////////////////////////////////////////////////////////////// +// private members +//////////////////////////////////////////////////////////////////////////////// + +void ASF::Properties::setLength(int length) +{ + d->length = length; +} + +void ASF::Properties::setBitrate(int length) +{ + d->bitrate = length; +} + +void ASF::Properties::setSampleRate(int length) +{ + d->sampleRate = length; +} + +void ASF::Properties::setChannels(int length) +{ + d->channels = length; +} diff --git a/Frameworks/TagLib/taglib/taglib/asf/asfproperties.h b/Frameworks/TagLib/taglib/taglib/asf/asfproperties.h new file mode 100644 index 000000000..653b015ea --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/asf/asfproperties.h @@ -0,0 +1,74 @@ +/************************************************************************** + copyright : (C) 2005-2007 by Lukáš Lalinský + email : lalinsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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_ASFPROPERTIES_H +#define TAGLIB_ASFPROPERTIES_H + +#include "audioproperties.h" +#include "tstring.h" +#include "taglib_export.h" + +namespace TagLib { + + namespace ASF { + + //! An implementation of ASF audio properties + class TAGLIB_EXPORT Properties : public AudioProperties + { + public: + + /*! + * Create an instance of ASF::Properties. + */ + Properties(); + + /*! + * Destroys this ASF::Properties instance. + */ + virtual ~Properties(); + + // Reimplementations. + virtual int length() const; + virtual int bitrate() const; + virtual int sampleRate() const; + virtual int channels() const; + +#ifndef DO_NOT_DOCUMENT + void setLength(int value); + void setBitrate(int value); + void setSampleRate(int value); + void setChannels(int value); +#endif + + private: + class PropertiesPrivate; + PropertiesPrivate *d; + }; + + } + +} + +#endif diff --git a/Frameworks/TagLib/taglib/taglib/asf/asftag.cpp b/Frameworks/TagLib/taglib/taglib/asf/asftag.cpp new file mode 100644 index 000000000..70b5d9057 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/asf/asftag.cpp @@ -0,0 +1,259 @@ +/************************************************************************** + copyright : (C) 2005-2007 by Lukáš Lalinský + email : lalinsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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/ * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "asftag.h" + +using namespace TagLib; + +class ASF::Tag::TagPrivate +{ +public: + String title; + String artist; + String copyright; + String comment; + String rating; + AttributeListMap attributeListMap; +}; + +ASF::Tag::Tag() +: TagLib::Tag() +{ + d = new TagPrivate; +} + +ASF::Tag::~Tag() +{ + if(d) + delete d; +} + +String +ASF::Tag::title() const +{ + return d->title; +} + +String +ASF::Tag::artist() const +{ + return d->artist; +} + +String +ASF::Tag::album() const +{ + if(d->attributeListMap.contains("WM/AlbumTitle")) + return d->attributeListMap["WM/AlbumTitle"][0].toString(); + return String::null; +} + +String +ASF::Tag::copyright() const +{ + return d->copyright; +} + +String +ASF::Tag::comment() const +{ + return d->comment; +} + +String +ASF::Tag::rating() const +{ + return d->rating; +} + +unsigned int +ASF::Tag::year() const +{ + if(d->attributeListMap.contains("WM/Year")) + return d->attributeListMap["WM/Year"][0].toString().toInt(); + return 0; +} + +unsigned int +ASF::Tag::track() const +{ + if(d->attributeListMap.contains("WM/TrackNumber")) { + const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0]; + if(attr.type() == ASF::Attribute::DWordType) + return attr.toUInt(); + else + return attr.toString().toInt(); + } + if(d->attributeListMap.contains("WM/Track")) + return d->attributeListMap["WM/Track"][0].toUInt(); + return 0; +} + +String +ASF::Tag::genre() const +{ + if(d->attributeListMap.contains("WM/Genre")) + return d->attributeListMap["WM/Genre"][0].toString(); + return String::null; +} + +float +ASF::Tag::rgAlbumGain() const +{ + return 0; +} + +float +ASF::Tag::rgAlbumPeak() const +{ + return 0; +} + +float +ASF::Tag::rgTrackGain() const +{ + return 0; +} + +float +ASF::Tag::rgTrackPeak() const +{ + return 0; +} + +void +ASF::Tag::setTitle(const String &value) +{ + d->title = value; +} + +void +ASF::Tag::setArtist(const String &value) +{ + d->artist = value; +} + +void +ASF::Tag::setCopyright(const String &value) +{ + d->copyright = value; +} + +void +ASF::Tag::setComment(const String &value) +{ + d->comment = value; +} + +void +ASF::Tag::setRating(const String &value) +{ + d->rating = value; +} + +void +ASF::Tag::setAlbum(const String &value) +{ + setAttribute("WM/AlbumTitle", value); +} + +void +ASF::Tag::setGenre(const String &value) +{ + setAttribute("WM/Genre", value); +} + +void +ASF::Tag::setYear(uint value) +{ + setAttribute("WM/Year", String::number(value)); +} + +void +ASF::Tag::setTrack(uint value) +{ + setAttribute("WM/TrackNumber", String::number(value)); +} + +void +ASF::Tag::setRGAlbumGain(float) +{ +} + +void +ASF::Tag::setRGAlbumPeak(float) +{ +} + +void +ASF::Tag::setRGTrackGain(float) +{ +} + +void +ASF::Tag::setRGTrackPeak(float) +{ +} + +ASF::AttributeListMap& +ASF::Tag::attributeListMap() +{ + return d->attributeListMap; +} + +void ASF::Tag::removeItem(const String &key) +{ + AttributeListMap::Iterator it = d->attributeListMap.find(key); + if(it != d->attributeListMap.end()) + d->attributeListMap.erase(it); +} + +void ASF::Tag::setAttribute(const String &name, const Attribute &attribute) +{ + AttributeList value; + value.append(attribute); + d->attributeListMap.insert(name, value); +} + +void ASF::Tag::addAttribute(const String &name, const Attribute &attribute) +{ + if(d->attributeListMap.contains(name)) { + d->attributeListMap[name].append(attribute); + } + else { + setAttribute(name, attribute); + } +} + +bool ASF::Tag::isEmpty() const { + return TagLib::Tag::isEmpty() && + copyright().isEmpty() && + rating().isEmpty() && + d->attributeListMap.isEmpty(); +} diff --git a/Frameworks/TagLib/taglib/taglib/asf/asftag.h b/Frameworks/TagLib/taglib/taglib/asf/asftag.h new file mode 100644 index 000000000..1de7ef796 --- /dev/null +++ b/Frameworks/TagLib/taglib/taglib/asf/asftag.h @@ -0,0 +1,196 @@ +/************************************************************************** + copyright : (C) 2005-2007 by Lukáš Lalinský + email : lalinsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * 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_ASFTAG_H +#define TAGLIB_ASFTAG_H + +#include "tag.h" +#include "tlist.h" +#include "tmap.h" +#include "taglib_export.h" +#include "asfattribute.h" + +namespace TagLib { + + namespace ASF { + + typedef List AttributeList; + typedef Map AttributeListMap; + + class TAGLIB_EXPORT Tag : public TagLib::Tag { + + friend class File; + + public: + + Tag(); + + virtual ~Tag(); + + /*! + * Returns the track name. + */ + virtual String title() const; + + /*! + * Returns the artist name. + */ + virtual String artist() const; + + /*! + * Returns the album name; if no album name is present in the tag + * String::null will be returned. + */ + virtual String album() const; + + /*! + * Returns the track comment. + */ + virtual String comment() const; + + /*! + * Returns the genre name; if no genre is present in the tag String::null + * will be returned. + */ + virtual String genre() const; + + /*! + * Returns the rating. + */ + virtual String rating() const; + + /*! + * Returns the genre name; if no genre is present in the tag String::null + * will be returned. + */ + virtual String copyright() const; + + /*! + * Returns the year; if there is no year set, this will return 0. + */ + virtual uint year() const; + + /*! + * Returns the track number; if there is no track number set, this will + * return 0. + */ + virtual uint track() const; + + virtual float rgAlbumGain() const; + virtual float rgAlbumPeak() const; + virtual float rgTrackGain() const; + virtual float rgTrackPeak() const; + + /*! + * Sets the title to \a s. + */ + virtual void setTitle(const String &s); + + /*! + * Sets the artist to \a s. + */ + virtual void setArtist(const String &s); + + /*! + * Sets the album to \a s. If \a s is String::null then this value will be + * cleared. + */ + virtual void setAlbum(const String &s); + + /*! + * Sets the comment to \a s. + */ + virtual void setComment(const String &s); + + /*! + * Sets the rating to \a s. + */ + virtual void setRating(const String &s); + + /*! + * Sets the copyright to \a s. + */ + virtual void setCopyright(const String &s); + + /*! + * Sets the genre to \a s. + */ + virtual void setGenre(const String &s); + + /*! + * Sets the year to \a i. If \a s is 0 then this value will be cleared. + */ + virtual void setYear(uint i); + + /*! + * Sets the track to \a i. If \a s is 0 then this value will be cleared. + */ + virtual void setTrack(uint i); + + virtual void setRGAlbumGain(float f); + virtual void setRGAlbumPeak(float f); + virtual void setRGTrackGain(float f); + virtual void setRGTrackPeak(float f); + + /*! + * Returns true if the tag does not contain any data. This should be + * reimplemented in subclasses that provide more than the basic tagging + * abilities in this class. + */ + virtual bool isEmpty() const; + + /*! + * Returns a reference to the item list map. This is an AttributeListMap of + * all of the items in the tag. + * + * This is the most powerfull structure for accessing the items of the tag. + */ + AttributeListMap &attributeListMap(); + + /*! + * Removes the \a key attribute from the tag + */ + void removeItem(const String &name); + + /*! + * Sets the \a key attribute to the value of \a attribute. If an attribute + * with the \a key is already present, it will be replaced. + */ + void setAttribute(const String &name, const Attribute &attribute); + + /*! + * Sets the \a key attribute to the value of \a attribute. If an attribute + * with the \a key is already present, it will be added to the list. + */ + void addAttribute(const String &name, const Attribute &attribute); + + private: + + class TagPrivate; + TagPrivate *d; + }; + } +} +#endif diff --git a/Frameworks/TagLib/taglib/taglib/fileref.cpp b/Frameworks/TagLib/taglib/taglib/fileref.cpp index 8f020fb21..1015f1602 100644 --- a/Frameworks/TagLib/taglib/taglib/fileref.cpp +++ b/Frameworks/TagLib/taglib/taglib/fileref.cpp @@ -1,6 +1,10 @@ /*************************************************************************** copyright : (C) 2002 - 2008 by Scott Wheeler email : wheeler@kde.org + + copyright : (C) 2010 by Alex Novichkov + email : novichko@atnet.ru + (added APE file support) ***************************************************************************/ /*************************************************************************** @@ -27,6 +31,7 @@ #include #include "fileref.h" +#include "asffile.h" #include "mpegfile.h" #include "vorbisfile.h" #include "flacfile.h" @@ -36,6 +41,7 @@ #include "speexfile.h" #include "trueaudiofile.h" #include "mp4file.h" +#include "apefile.h" using namespace TagLib; @@ -123,6 +129,13 @@ StringList FileRef::defaultFileExtensions() l.append("spx"); l.append("tta"); l.append("m4a"); + l.append("m4b"); + l.append("m4p"); + l.append("3g2"); + l.append("mp4"); + l.append("wma"); + l.append("asf"); + l.append("ape"); return l; } @@ -182,25 +195,36 @@ File *FileRef::create(FileName fileName, bool readAudioProperties, // updated. However at some point that list should be created at the same time // that a default file type resolver is created. - if(s.size() > 4) { - if(s.substr(s.size() - 4, 4).upper() == ".OGG") - return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); - if(s.substr(s.size() - 4, 4).upper() == ".MP3") + int pos = s.rfind("."); + if(pos != -1) { + String ext = s.substr(pos + 1).upper(); + if(ext == "MP3") return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); - if(s.substr(s.size() - 4, 4).upper() == ".OGA") - return new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); - if(s.substr(s.size() - 5, 5).upper() == ".FLAC") + if(ext == "OGG") + return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); + if(ext == "OGA") { + 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(s.substr(s.size() - 4, 4).upper() == ".MPC") + if(ext == "MPC") return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle); - if(s.substr(s.size() - 3, 3).upper() == ".WV") + if(ext == "WV") return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle); - if(s.substr(s.size() - 4, 4).upper() == ".SPX") + if(ext == "SPX") return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle); - if(s.substr(s.size() - 4, 4).upper() == ".TTA") + if(ext == "TTA") return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle); - if(s.substr(s.size() - 4, 4).upper() == ".M4A") + if(ext == "M4A" || 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 == "APE") + return new APE::File(fileName, readAudioProperties, audioPropertiesStyle); } return 0; diff --git a/Frameworks/TagLib/taglib/taglib/toolkit/tstring.cpp b/Frameworks/TagLib/taglib/taglib/toolkit/tstring.cpp index b9a429387..8d3059298 100644 --- a/Frameworks/TagLib/taglib/taglib/toolkit/tstring.cpp +++ b/Frameworks/TagLib/taglib/taglib/toolkit/tstring.cpp @@ -295,6 +295,17 @@ int String::find(const String &s, int offset) const return -1; } +int String::rfind(const String &s, int offset) const +{ + wstring::size_type position = + d->data.rfind(s.d->data, offset == -1 ? wstring::npos : offset); + + if(position != wstring::npos) + return position; + else + return -1; +} + bool String::startsWith(const String &s) const { if(s.length() > length()) diff --git a/Frameworks/TagLib/taglib/taglib/toolkit/tstring.h b/Frameworks/TagLib/taglib/taglib/toolkit/tstring.h index 15b575862..ef2c508d6 100644 --- a/Frameworks/TagLib/taglib/taglib/toolkit/tstring.h +++ b/Frameworks/TagLib/taglib/taglib/toolkit/tstring.h @@ -225,6 +225,13 @@ namespace TagLib { */ int find(const String &s, int offset = 0) const; + /*! + * Finds the last occurrence of pattern \a s in this string, searched backwards, + * either from the end of the string or starting from \a offset. If the pattern + * is not found, -1 is returned. + */ + int rfind(const String &s, int offset = -1) const; + /*! * Returns true if the strings starts with the substring \a s. */ diff --git a/Plugins/TagLib/TagLibMetadataReader.m b/Plugins/TagLib/TagLibMetadataReader.m index ff6672de0..1e51894db 100644 --- a/Plugins/TagLib/TagLibMetadataReader.m +++ b/Plugins/TagLib/TagLibMetadataReader.m @@ -174,12 +174,12 @@ + (NSArray *)fileTypes { //May be a way to get a list of supported formats - return [NSArray arrayWithObjects:@"ogg", @"mpc", @"flac", @"m4a", @"mp3", nil]; + return [NSArray arrayWithObjects:@"ape", @"asf", @"wma", @"ogg", @"mpc", @"flac", @"m4a", @"mp3", nil]; } + (NSArray *)mimeTypes { - return [NSArray arrayWithObjects:@"application/ogg", @"application/x-ogg", @"audio/x-vorbis+ogg", @"audio/x-musepack", @"audio/x-flac", @"audio/x-m4a", @"audio/mpeg", @"audio/x-mp3", nil]; + return [NSArray arrayWithObjects:@"audio/x-ape", @"audio/x-ms-wma", @"application/ogg", @"application/x-ogg", @"audio/x-vorbis+ogg", @"audio/x-musepack", @"audio/x-flac", @"audio/x-m4a", @"audio/mpeg", @"audio/x-mp3", nil]; } @end