strawberry-audio-player-win.../3rdparty/taglib/ape/apeitem.cpp

272 lines
6.8 KiB
C++
Raw Normal View History

2018-05-10 15:29:28 +02:00
/***************************************************************************
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., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
2020-06-26 23:30:30 +02:00
#include <memory>
#include "tbytevectorlist.h"
#include "tdebug.h"
2018-05-10 15:29:28 +02:00
#include "apeitem.h"
using namespace Strawberry_TagLib::TagLib;
2018-05-10 15:29:28 +02:00
using namespace APE;
2020-06-26 23:30:30 +02:00
struct ItemData {
ItemData() : type(Item::Text), readOnly(false) {}
2018-05-10 15:29:28 +02:00
Item::ItemTypes type;
String key;
ByteVector value;
StringList text;
bool readOnly;
};
2020-06-26 23:30:30 +02:00
class APE::Item::ItemPrivate {
public:
ItemPrivate() : data(new ItemData()) {}
std::shared_ptr<ItemData> data;
};
2018-05-10 15:29:28 +02:00
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
APE::Item::Item() : d(new ItemPrivate()) {}
2018-05-10 15:29:28 +02:00
2020-06-26 23:30:30 +02:00
APE::Item::Item(const String &key, const String &value) : d(new ItemPrivate()) {
d->data->key = key;
d->data->text.append(value);
}
2020-06-13 19:02:42 +02:00
APE::Item::Item(const String &key, const StringList &values) : d(new ItemPrivate()) {
2020-06-26 23:30:30 +02:00
d->data->key = key;
d->data->text = values;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
APE::Item::Item(const String &key, const ByteVector &value, bool binary) : d(new ItemPrivate()) {
2020-06-26 23:30:30 +02:00
d->data->key = key;
2020-06-13 19:02:42 +02:00
if (binary) {
2020-06-26 23:30:30 +02:00
d->data->type = Binary;
d->data->value = value;
2018-05-10 15:29:28 +02:00
}
else {
2020-06-26 23:30:30 +02:00
d->data->text.append(value);
2018-05-10 15:29:28 +02:00
}
}
APE::Item::Item(const Item &item) : d(new ItemPrivate(*item.d)) {}
2020-06-13 19:02:42 +02:00
APE::Item::~Item() {
2018-05-10 15:29:28 +02:00
delete d;
}
2020-06-13 19:02:42 +02:00
Item &APE::Item::operator=(const Item &item) {
2018-05-10 15:29:28 +02:00
Item(item).swap(*this);
return *this;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::swap(Item &item) {
2018-05-10 15:29:28 +02:00
using std::swap;
swap(d, item.d);
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::setReadOnly(bool readOnly) {
2020-06-26 23:30:30 +02:00
d->data->readOnly = readOnly;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
bool APE::Item::isReadOnly() const {
2020-06-26 23:30:30 +02:00
return d->data->readOnly;
2018-05-10 15:29:28 +02:00
}
2020-06-26 23:30:30 +02:00
void APE::Item::setType(APE::Item::ItemTypes val) {
d->data->type = val;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
APE::Item::ItemTypes APE::Item::type() const {
2020-06-26 23:30:30 +02:00
return d->data->type;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
String APE::Item::key() const {
2020-06-26 23:30:30 +02:00
return d->data->key;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
ByteVector APE::Item::binaryData() const {
2020-06-26 23:30:30 +02:00
return d->data->value;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::setBinaryData(const ByteVector &value) {
2020-06-26 23:30:30 +02:00
d->data->type = Binary;
d->data->value = value;
d->data->text.clear();
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::setKey(const String &key) {
2020-06-26 23:30:30 +02:00
d->data->key = key;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::setValue(const String &value) {
2020-06-26 23:30:30 +02:00
d->data->type = Text;
d->data->text = value;
d->data->value.clear();
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::setValues(const StringList &value) {
2020-06-26 23:30:30 +02:00
d->data->type = Text;
d->data->text = value;
d->data->value.clear();
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::appendValue(const String &value) {
2020-06-26 23:30:30 +02:00
d->data->type = Text;
d->data->text.append(value);
d->data->value.clear();
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::appendValues(const StringList &values) {
2020-06-26 23:30:30 +02:00
d->data->type = Text;
d->data->text.append(values);
d->data->value.clear();
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
int APE::Item::size() const {
2020-06-26 23:30:30 +02:00
size_t result = 8 + d->data->key.size() + 1;
switch (d->data->type) {
2018-05-10 15:29:28 +02:00
case Text:
2020-06-26 23:30:30 +02:00
if (!d->data->text.isEmpty()) {
StringList::ConstIterator it = d->data->text.begin();
2018-05-10 15:29:28 +02:00
result += it->data(String::UTF8).size();
it++;
2020-06-26 23:30:30 +02:00
for (; it != d->data->text.end(); ++it)
2018-05-10 15:29:28 +02:00
result += 1 + it->data(String::UTF8).size();
}
break;
case Binary:
case Locator:
2020-06-26 23:30:30 +02:00
result += d->data->value.size();
2018-05-10 15:29:28 +02:00
break;
}
return result;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
StringList APE::Item::values() const {
2020-06-26 23:30:30 +02:00
return d->data->text;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
String APE::Item::toString() const {
2020-06-26 23:30:30 +02:00
if (d->data->type == Text && !isEmpty())
return d->data->text.front();
2018-05-10 15:29:28 +02:00
else
return String();
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
bool APE::Item::isEmpty() const {
2020-06-26 23:30:30 +02:00
switch (d->data->type) {
2018-05-10 15:29:28 +02:00
case Text:
2020-06-26 23:30:30 +02:00
if (d->data->text.isEmpty())
2018-05-10 15:29:28 +02:00
return true;
2020-06-26 23:30:30 +02:00
if (d->data->text.size() == 1 && d->data->text.front().isEmpty())
2018-05-10 15:29:28 +02:00
return true;
return false;
case Binary:
case Locator:
2020-06-26 23:30:30 +02:00
return d->data->value.isEmpty();
2018-05-10 15:29:28 +02:00
default:
return false;
}
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
void APE::Item::parse(const ByteVector &data) {
2018-05-10 15:29:28 +02:00
// 11 bytes is the minimum size for an APE item
2020-06-13 19:02:42 +02:00
if (data.size() < 11) {
2018-05-10 15:29:28 +02:00
debug("APE::Item::parse() -- no data in item");
return;
}
2020-06-26 23:30:30 +02:00
const unsigned int valueLength = data.toUInt32LE(0);
const unsigned int flags = data.toUInt32LE(4);
2018-05-10 15:29:28 +02:00
// An item key can contain ASCII characters from 0x20 up to 0x7E, not UTF-8.
// We assume that the validity of the given key has been checked.
2020-06-26 23:30:30 +02:00
d->data->key = String(&data[8], String::Latin1);
2018-05-10 15:29:28 +02:00
2020-06-26 23:30:30 +02:00
const ByteVector value = data.mid(8 + d->data->key.size() + 1, valueLength);
2018-05-10 15:29:28 +02:00
setReadOnly(flags & 1);
setType(ItemTypes((flags >> 1) & 3));
2020-06-26 23:30:30 +02:00
if (Text == d->data->type)
d->data->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
2018-05-10 15:29:28 +02:00
else
2020-06-26 23:30:30 +02:00
d->data->value = value;
2018-05-10 15:29:28 +02:00
}
2020-06-13 19:02:42 +02:00
ByteVector APE::Item::render() const {
2018-05-10 15:29:28 +02:00
ByteVector data;
2020-06-26 23:30:30 +02:00
unsigned int flags = ((d->data->readOnly) ? 1 : 0) | (d->data->type << 1);
2018-05-10 15:29:28 +02:00
ByteVector value;
2020-06-13 19:02:42 +02:00
if (isEmpty())
2018-05-10 15:29:28 +02:00
return data;
2020-06-26 23:30:30 +02:00
if (d->data->type == Text) {
StringList::ConstIterator it = d->data->text.begin();
2018-05-10 15:29:28 +02:00
value.append(it->data(String::UTF8));
it++;
2020-06-26 23:30:30 +02:00
for (; it != d->data->text.end(); ++it) {
2018-05-10 15:29:28 +02:00
value.append('\0');
value.append(it->data(String::UTF8));
}
2020-06-26 23:30:30 +02:00
d->data->value = value;
2018-05-10 15:29:28 +02:00
}
else
2020-06-26 23:30:30 +02:00
value.append(d->data->value);
2018-05-10 15:29:28 +02:00
2020-06-26 23:30:30 +02:00
data.append(ByteVector::fromUInt32LE(value.size()));
data.append(ByteVector::fromUInt32LE(flags));
data.append(d->data->key.data(String::Latin1));
2018-05-10 15:29:28 +02:00
data.append(ByteVector('\0'));
data.append(value);
return data;
2018-05-10 15:29:28 +02:00
}