summaryrefslogtreecommitdiff
path: root/libs/taglib/taglib/ape/apetag.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/taglib/taglib/ape/apetag.cpp')
-rw-r--r--libs/taglib/taglib/ape/apetag.cpp266
1 files changed, 266 insertions, 0 deletions
diff --git a/libs/taglib/taglib/ape/apetag.cpp b/libs/taglib/taglib/ape/apetag.cpp
new file mode 100644
index 0000000000..1c38d2bdd0
--- /dev/null
+++ b/libs/taglib/taglib/ape/apetag.cpp
@@ -0,0 +1,266 @@
+/***************************************************************************
+ copyright : (C) 2004 by Allan Sandfeld Jensen
+ email : kde@carewolf.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 __SUNPRO_CC
+// Sun Studio finds multiple specializations of Map because
+// it considers specializations with and without class types
+// to be different; this define forces Map to use only the
+// specialization with the class keyword.
+#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
+#endif
+
+#include <tfile.h>
+#include <tstring.h>
+#include <tmap.h>
+
+#include "apetag.h"
+#include "apefooter.h"
+#include "apeitem.h"
+
+using namespace TagLib;
+using namespace APE;
+
+class APE::Tag::TagPrivate
+{
+public:
+ TagPrivate() : file(0), footerLocation(-1), tagLength(0) {}
+
+ File *file;
+ long footerLocation;
+ long tagLength;
+
+ Footer footer;
+
+ ItemListMap itemListMap;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public methods
+////////////////////////////////////////////////////////////////////////////////
+
+APE::Tag::Tag() : TagLib::Tag()
+{
+ d = new TagPrivate;
+}
+
+APE::Tag::Tag(File *file, long footerLocation) : TagLib::Tag()
+{
+ d = new TagPrivate;
+ d->file = file;
+ d->footerLocation = footerLocation;
+
+ read();
+}
+
+APE::Tag::~Tag()
+{
+ delete d;
+}
+
+ByteVector APE::Tag::fileIdentifier()
+{
+ return ByteVector::fromCString("APETAGEX");
+}
+
+String APE::Tag::title() const
+{
+ if(d->itemListMap["TITLE"].isEmpty())
+ return String::null;
+ return d->itemListMap["TITLE"].toString();
+}
+
+String APE::Tag::artist() const
+{
+ if(d->itemListMap["ARTIST"].isEmpty())
+ return String::null;
+ return d->itemListMap["ARTIST"].toString();
+}
+
+String APE::Tag::album() const
+{
+ if(d->itemListMap["ALBUM"].isEmpty())
+ return String::null;
+ return d->itemListMap["ALBUM"].toString();
+}
+
+String APE::Tag::comment() const
+{
+ if(d->itemListMap["COMMENT"].isEmpty())
+ return String::null;
+ return d->itemListMap["COMMENT"].toString();
+}
+
+String APE::Tag::genre() const
+{
+ if(d->itemListMap["GENRE"].isEmpty())
+ return String::null;
+ return d->itemListMap["GENRE"].toString();
+}
+
+TagLib::uint APE::Tag::year() const
+{
+ if(d->itemListMap["YEAR"].isEmpty())
+ return 0;
+ return d->itemListMap["YEAR"].toString().toInt();
+}
+
+TagLib::uint APE::Tag::track() const
+{
+ if(d->itemListMap["TRACK"].isEmpty())
+ return 0;
+ return d->itemListMap["TRACK"].toString().toInt();
+}
+
+void APE::Tag::setTitle(const String &s)
+{
+ addValue("TITLE", s, true);
+}
+
+void APE::Tag::setArtist(const String &s)
+{
+ addValue("ARTIST", s, true);
+}
+
+void APE::Tag::setAlbum(const String &s)
+{
+ addValue("ALBUM", s, true);
+}
+
+void APE::Tag::setComment(const String &s)
+{
+ addValue("COMMENT", s, true);
+}
+
+void APE::Tag::setGenre(const String &s)
+{
+ addValue("GENRE", s, true);
+}
+
+void APE::Tag::setYear(uint i)
+{
+ if(i <= 0)
+ removeItem("YEAR");
+ else
+ addValue("YEAR", String::number(i), true);
+}
+
+void APE::Tag::setTrack(uint i)
+{
+ if(i <= 0)
+ removeItem("TRACK");
+ else
+ addValue("TRACK", String::number(i), true);
+}
+
+APE::Footer *APE::Tag::footer() const
+{
+ return &d->footer;
+}
+
+const APE::ItemListMap& APE::Tag::itemListMap() const
+{
+ return d->itemListMap;
+}
+
+void APE::Tag::removeItem(const String &key)
+{
+ Map<const String, Item>::Iterator it = d->itemListMap.find(key.upper());
+ if(it != d->itemListMap.end())
+ d->itemListMap.erase(it);
+}
+
+void APE::Tag::addValue(const String &key, const String &value, bool replace)
+{
+ if(replace)
+ removeItem(key);
+ if(!value.isEmpty()) {
+ if(d->itemListMap.contains(key) || !replace)
+ d->itemListMap[key.upper()].appendValue(value);
+ else
+ setItem(key, Item(key, value));
+ }
+}
+
+void APE::Tag::setItem(const String &key, const Item &item)
+{
+ d->itemListMap.insert(key.upper(), item);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// protected methods
+////////////////////////////////////////////////////////////////////////////////
+
+void APE::Tag::read()
+{
+ if(d->file && d->file->isValid()) {
+
+ d->file->seek(d->footerLocation);
+ d->footer.setData(d->file->readBlock(Footer::size()));
+
+ if(d->footer.tagSize() <= Footer::size() ||
+ d->footer.tagSize() > uint(d->file->length()))
+ return;
+
+ d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
+ parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
+ }
+}
+
+ByteVector APE::Tag::render() const
+{
+ ByteVector data;
+ uint itemCount = 0;
+
+ {
+ for(Map<const String, Item>::ConstIterator it = d->itemListMap.begin();
+ it != d->itemListMap.end(); ++it)
+ {
+ data.append(it->second.render());
+ itemCount++;
+ }
+ }
+
+ d->footer.setItemCount(itemCount);
+ d->footer.setTagSize(data.size() + Footer::size());
+ d->footer.setHeaderPresent(true);
+
+ return d->footer.renderHeader() + data + d->footer.renderFooter();
+}
+
+void APE::Tag::parse(const ByteVector &data)
+{
+ uint pos = 0;
+
+ // 11 bytes is the minimum size for an APE item
+
+ for(uint i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
+ APE::Item item;
+ item.parse(data.mid(pos));
+
+ d->itemListMap.insert(item.key().upper(), item);
+
+ pos += item.size();
+ }
+}