mirror of
https://github.com/taglib/taglib.git
synced 2025-05-27 21:20:26 -04:00
Update interface. Just needs more documentation now.
git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@340209 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
This commit is contained in:
parent
d0095d3cd7
commit
3ab81ed05d
@ -5,7 +5,7 @@ INCLUDES = \
|
||||
|
||||
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
|
||||
|
@ -181,7 +181,7 @@ void Footer::parse(const ByteVector &data)
|
||||
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];
|
||||
|
167
ape/apeitem.cpp
Normal file
167
ape/apeitem.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
/***************************************************************************
|
||||
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;
|
||||
}
|
90
ape/apeitem.h
Normal file
90
ape/apeitem.h
Normal file
@ -0,0 +1,90 @@
|
||||
/***************************************************************************
|
||||
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
|
||||
|
||||
|
134
ape/apetag.cpp
134
ape/apetag.cpp
@ -26,37 +26,11 @@
|
||||
|
||||
#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;
|
||||
@ -71,7 +45,7 @@ static StringList parseAPEString(const ByteVector &data)
|
||||
value.append(String(data.mid(pOld), String::UTF8));
|
||||
|
||||
return value;
|
||||
}
|
||||
}*/
|
||||
|
||||
class APE::Tag::TagPrivate
|
||||
{
|
||||
@ -85,24 +59,8 @@ public:
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -126,40 +84,6 @@ APE::Tag::~Tag()
|
||||
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");
|
||||
@ -169,49 +93,49 @@ String APE::Tag::title() const
|
||||
{
|
||||
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)
|
||||
@ -278,9 +202,9 @@ void APE::Tag::addValue(const String &key, const String &value, bool replace)
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,24 +233,38 @@ void APE::Tag::read()
|
||||
}
|
||||
}
|
||||
|
||||
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--;
|
||||
}
|
||||
}
|
||||
|
20
ape/apetag.h
20
ape/apetag.h
@ -28,6 +28,8 @@
|
||||
#include "tstring.h"
|
||||
#include "tstringlist.h"
|
||||
|
||||
#include "apeitem.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class File;
|
||||
@ -36,22 +38,6 @@ namespace TagLib {
|
||||
|
||||
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.
|
||||
@ -120,7 +106,7 @@ namespace TagLib {
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user