noinst_LTLIBRARIES = libape.la
-libape_la_SOURCES = apetag.cpp apefooter.cpp
+libape_la_SOURCES = apetag.cpp apefooter.cpp apeitem.cpp
taglib_include_HEADERS = apetag.h apefooter.h
taglib_includedir = $(includedir)/taglib
d->itemCount = data.mid(16, 4).toUInt(false);
// Read the flags
- std::bitset<32> flags(data.mid(8, 4).toUInt(false));
+ std::bitset<32> flags(data.mid(20, 4).toUInt(false));
d->headerPresent = flags[31];
d->footerPresent = !flags[30];
--- /dev/null
+/***************************************************************************
+ 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 *
+ ***************************************************************************/
+
+#include "apeitem.h"
+#include "tbytevectorlist.h"
+#include "tstringlist.h"
+#include <iostream>
+
+using std::cout;
+
+using namespace TagLib;
+using namespace APE;
+
+
+class APE::Item::ItemPrivate
+{
+public:
+ ItemPrivate() : type(Text), readOnly(false) {}
+
+ Item::ItemTypes type;
+ String key;
+ ByteVector value;
+ StringList text;
+ bool readOnly;
+};
+
+APE::Item::Item()
+{
+ d = new ItemPrivate;
+}
+
+APE::Item::Item(const String& key, const String& str)
+{
+ d = new ItemPrivate;
+ d->key = key;
+ d->text.append(str);
+}
+
+APE::Item::Item(const Item& item)
+{
+ d = new ItemPrivate(*item.d);
+}
+
+Item& APE::Item::operator=(const Item& item)
+{
+ delete d;
+ d = new ItemPrivate(*item.d);
+ return *this;
+}
+
+void APE::Item::setReadOnly(bool val) {
+ d->readOnly = val;
+}
+
+bool APE::Item::isReadOnly() const {
+ return d->readOnly;
+}
+
+void APE::Item::setType(APE::Item::ItemTypes val) {
+ d->type = val;
+}
+
+APE::Item::ItemTypes APE::Item::type() const {
+ return d->type;
+}
+
+String APE::Item::key() const {
+ return d->key;
+}
+
+ByteVector APE::Item::value() const {
+ return d->value;
+}
+
+int APE::Item::size() const {
+ return 8 + d->key.size() + 1 + d->value.size();
+}
+
+StringList APE::Item::toStringList() const {
+ return d->text;
+}
+
+String APE::Item::toString() const {
+ return d->text.front();
+}
+
+bool APE::Item::isEmpty() const {
+ switch(d->type) {
+ case 0:
+ case 1:
+ if(d->text.isEmpty()) return true;
+ if(d->text.size() == 1 && d->text.front() == "") return true;
+ return false;
+ case 2:
+ return d->value.isEmpty();
+ default:
+ return false;
+ }
+}
+
+void APE::Item::parse(const ByteVector& data) {
+ uint valueLength = data.mid(0, 4).toUInt(false);
+ uint flags = data.mid(4, 4).toUInt(false);
+
+ d->key = String(data.mid(8), String::UTF8);
+
+ d->value = data.mid(8 + d->key.size() + 1, valueLength);
+
+ setReadOnly(flags & 1);
+ setType(ItemTypes((flags >> 1) & 3));
+
+ if ((int)(d->type) < 2) {
+ ByteVectorList bl = ByteVectorList::split(d->value, '\0');
+ d->text = StringList(bl, String::UTF8);
+ cout << d->text.toString(",") << "\n";
+ }
+
+}
+
+ByteVector APE::Item::render()
+{
+ ByteVector data;
+ TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
+ ByteVector value;
+
+ if(isEmpty())
+ return data;
+
+ if(d->type != Item::Binary) {
+ StringList::ConstIterator it = d->text.begin();
+ value.append(it->data(String::UTF8));
+ it++;
+ while(it != d->text.end()) {
+ value.append('\0');
+ value.append(it->data(String::UTF8));
+ it++;
+ }
+ d->value = value;
+ } else
+ value.append(d->value);
+
+ data.append(ByteVector::fromUInt(value.size(), false));
+ data.append(ByteVector::fromUInt(flags, false));
+ data.append(d->key.data(String::UTF8));
+ data.append(ByteVector('\0'));
+ data.append(value);
+
+ return data;
+}
--- /dev/null
+/***************************************************************************
+ copyright : (C) 2004 by Allan Sandfeld Jensen
+ email : kde@carewolf.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * 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 *
+ ***************************************************************************/
+
+#ifndef TAGLIB_APEITEM_H
+#define TAGLIB_APEITEM_H
+
+#include <tbytevector.h>
+#include <tstring.h>
+#include <tstringlist.h>
+
+namespace TagLib {
+
+ namespace APE {
+
+ //! An implementation of APE-items
+
+ /*!
+ * This class provides the features of items in the APEv2 standard.
+ */
+ struct Item
+ {
+ enum ItemTypes {
+ //! Item contains text information coded in UTF-8
+ Text = 0,
+ //! Item contains binary information
+ Binary = 1,
+ //! Item is a locator of external stored information
+ Locator = 2
+ };
+ Item();
+ explicit Item(ByteVector& bin);
+ explicit Item(const String&, const String&);
+ explicit Item(const String&, const StringList &);
+ Item(const Item&);
+ Item& operator=(const Item&);
+
+ String key() const;
+ ByteVector value() const;
+
+ int size() const;
+
+ String toString() const;
+ StringList toStringList() const;
+
+ ByteVector render();
+ void parse(const ByteVector&);
+
+ void setReadOnly(bool);
+
+ bool isReadOnly() const;
+
+ void setType(ItemTypes type);
+
+ ItemTypes type() const;
+/*
+ void setValue(ByteVector);
+ void setValue(const String&);
+ void setValue(const StringList&);
+ */
+ bool isEmpty() const;
+
+ private:
+ class ItemPrivate;
+ ItemPrivate *d;
+ };
+ }
+
+}
+
+#endif
+
+
#include "apetag.h"
#include "apefooter.h"
+#include "apeitem.h"
using namespace TagLib;
using namespace APE;
-
-static ByteVector renderAPEItem(const String &key, const Item &item)
-{
- ByteVector data;
- TagLib::uint flags = ((item.readOnly) ? 1 : 0) | ((item.locator) ? 2 : 0);
- ByteVector value;
-
- if(item.value.isEmpty())
- return data;
-
- StringList::ConstIterator it = item.value.begin();
- value.append(it->data(String::UTF8));
- it++;
- while(it != item.value.end()) {
- value.append('\0');
- value.append(it->data(String::UTF8));
- it++;
- }
-
- data.append(ByteVector::fromUInt(value.size(), false));
- data.append(ByteVector::fromUInt(flags, false));
- data.append(key.data(String::UTF8));
- data.append(ByteVector('\0'));
- data.append(value);
-
- return data;
-}
-
+/*
static StringList parseAPEString(const ByteVector &data)
{
StringList value;
value.append(String(data.mid(pOld), String::UTF8));
return value;
-}
+}*/
class APE::Tag::TagPrivate
{
Footer footer;
ItemListMap itemListMap;
- Map<const String, ByteVector> binaries;
};
-APE::Item::Item(const String& str) : readOnly(false), locator(false)
-{
- value.append(str);
-}
-
-APE::Item::Item(const StringList& values) : readOnly(false), locator(false)
-{
- value.append(values);
-}
-
-bool APE::Item::isEmpty() const
-{
- return value.isEmpty();
-}
-
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
delete d;
}
-ByteVector APE::Tag::render() const
-{
- ByteVector data;
- uint itemCount = 0;
-
- {
- Map<const String,Item>::Iterator i = d->itemListMap.begin();
- while(i != d->itemListMap.end()) {
- if(!i->second.value.isEmpty()) {
- data.append(renderAPEItem(i->first, i->second));
- itemCount++;
- }
- i++;
- }
- }
-
- {
- Map<String,ByteVector>::Iterator i = d->binaries.begin();
- while(i != d->binaries.end()) {
- if(!i->second.isEmpty()) {
- data.append(i->second);
- itemCount++;
- }
- i++;
- }
- }
-
- d->footer.setItemCount(itemCount);
- d->footer.setTagSize(data.size()+Footer::size());
- d->footer.setHeaderPresent(true);
-
- return d->footer.renderHeader() + data + d->footer.renderFooter();
-}
-
ByteVector APE::Tag::fileIdentifier()
{
return ByteVector::fromCString("APETAGEX");
{
if(d->itemListMap["TITLE"].isEmpty())
return String::null;
- return d->itemListMap["TITLE"].value.front();
+ return d->itemListMap["TITLE"].toString();
}
String APE::Tag::artist() const
{
if(d->itemListMap["ARTIST"].isEmpty())
return String::null;
- return d->itemListMap["ARTIST"].value.front();
+ return d->itemListMap["ARTIST"].toString();
}
String APE::Tag::album() const
{
if(d->itemListMap["ALBUM"].isEmpty())
return String::null;
- return d->itemListMap["ALBUM"].value.front();
+ return d->itemListMap["ALBUM"].toString();
}
String APE::Tag::comment() const
{
if(d->itemListMap["COMMENT"].isEmpty())
return String::null;
- return d->itemListMap["COMMENT"].value.front();
+ return d->itemListMap["COMMENT"].toString();
}
String APE::Tag::genre() const
{
if(d->itemListMap["GENRE"].isEmpty())
return String::null;
- return d->itemListMap["GENRE"].value.front();
+ return d->itemListMap["GENRE"].toString();
}
TagLib::uint APE::Tag::year() const
{
if(d->itemListMap["YEAR"].isEmpty())
return 0;
- return d->itemListMap["YEAR"].value.front().toInt();
+ return d->itemListMap["YEAR"].toString().toInt();
}
TagLib::uint APE::Tag::track() const
{
if(d->itemListMap["TRACK"].isEmpty())
return 0;
- return d->itemListMap["TRACK"].value.front().toInt();
+ return d->itemListMap["TRACK"].toString().toInt();
}
void APE::Tag::setTitle(const String &s)
removeItem(key);
if(!value.isEmpty()) {
if(d->itemListMap.contains(key) || !replace)
- d->itemListMap[key.upper()].value.append(value);
+ d->itemListMap[key.upper()].toStringList().append(value);
else
- setItem(key, Item(value));
+ setItem(key, Item(key, value));
}
}
}
}
+ByteVector APE::Tag::render() const
+{
+ ByteVector data;
+ uint itemCount = 0;
+
+ {
+ Map<const String,Item>::Iterator i = d->itemListMap.begin();
+ while(i != d->itemListMap.end()) {
+ data.append(i->second.render());
+ itemCount++;
+ i++;
+ }
+ }
+
+ 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 count)
{
uint pos = 0;
while(count > 0) {
- uint valueLength = data.mid(pos + 0, 4).toUInt(false);
- uint flags = data.mid(pos + 4, 4).toUInt(false);
- String key = String(data.mid(pos + 8), String::UTF8);
APE::Item item;
+ item.parse(data.mid(pos));
- if(flags < 4 ) {
- ByteVector val = data.mid(pos + 8 + key.size() + 1, valueLength);
- d->itemListMap.insert(key.upper(), Item(parseAPEString(val)));
- }
- else
- d->binaries.insert(key.upper(), data.mid(pos, 8 + key.size() + 1 + valueLength));
+ d->itemListMap.insert(item.key().upper(), item);
- pos += 8 + key.size() + 1 + valueLength;
+ pos += item.size();
count--;
}
}
#include "tstring.h"
#include "tstringlist.h"
+#include "apeitem.h"
+
namespace TagLib {
class File;
class Footer;
- /*!
- * A non-binary APE-item.
- */
- struct Item
- {
- Item() {};
- explicit Item(const String &);
- explicit Item(const StringList &);
- bool readOnly;
- /*!
- * The value is a URL to external data
- */
- bool locator;
- StringList value;
- bool isEmpty() const;
- };
/*!
* A mapping between a list of item names, or keys, and the associated item.
const ItemListMap &itemListMap() const;
/*!
- * Removes the \a key comment from the tag
+ * Removes the \a key item from the tag
*/
void removeItem(const String &key);