1
0
mirror of https://github.com/strawberrymusicplayer/strawberry synced 2025-02-07 23:38:48 +01:00

Adapt most changes from taglib2

This commit is contained in:
Jonas Kvinge 2020-06-26 23:30:30 +02:00
parent 08882639e0
commit 5f71a558b9
374 changed files with 13708 additions and 4418 deletions

View File

@ -1133,7 +1133,7 @@ jobs:
GST_SCANNER_PATH: /usr/local/opt/gstreamer/libexec/gstreamer-1.0/gst-plugin-scanner
GST_PLUGIN_PATH: /usr/local/lib/gstreamer-1.0
working-directory: build
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DUSE_BUNDLE=ON -DUSE_SYSTEM_TAGLIB=OFF
run: cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DUSE_BUNDLE=ON
- name: Build
working-directory: build
shell: bash
@ -1180,8 +1180,6 @@ jobs:
-DENABLE_IMOBILEDEVICE=OFF
-DENABLE_LIBMTP=OFF
-DENABLE_XINE=OFF
-DUSE_SYSTEM_SINGLEAPPLICATION=OFF
-DUSE_SYSTEM_TAGLIB=OFF
-DProtobuf_PROTOC_EXECUTABLE=/usr/src/strawberry-mxe/usr/x86_64-pc-linux-gnu/bin/protoc
- name: Run Make

View File

@ -33,7 +33,7 @@ before_install:
fi
before_script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DUSE_BUNDLE=ON -DUSE_SYSTEM_TAGLIB=OFF ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DUSE_BUNDLE=ON ; fi
script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then

View File

@ -8,17 +8,9 @@ math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSI
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}")
include(TestBigEndian)
test_big_endian(IS_BIG_ENDIAN)
if(NOT IS_BIG_ENDIAN)
add_definitions(-DSYSTEM_BYTEORDER=1)
else()
add_definitions(-DSYSTEM_BYTEORDER=2)
endif()
include(ConfigureChecks.cmake)
configure_file(config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h")
set(TESTS_DIR "${CMAKE_SOURCE_DIR}/tests/taglib/")
configure_file(taglib-config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.h")
add_definitions(-DHAVE_CONFIG_H)
add_definitions(-DTAGLIB_STATIC)
@ -33,6 +25,7 @@ set(tag_HDRS
toolkit/tlist.h
toolkit/tlist.tcc
toolkit/tstringlist.h
toolkit/tstringhandler.h
toolkit/tbytevector.h
toolkit/tbytevectorlist.h
toolkit/tbytevectorstream.h
@ -41,6 +34,8 @@ set(tag_HDRS
toolkit/tfilestream.h
toolkit/tmap.h
toolkit/tmap.tcc
toolkit/tpicture.h
toolkit/tpicturemap.h
toolkit/tpropertymap.h
toolkit/trefcounter.h
toolkit/tdebuglistener.h
@ -300,8 +295,10 @@ set(dsdiff_SRCS
)
set(toolkit_SRCS
toolkit/taglib.cpp
toolkit/tstring.cpp
toolkit/tstringlist.cpp
toolkit/tstringhandler.cpp
toolkit/tbytevector.cpp
toolkit/tbytevectorlist.cpp
toolkit/tbytevectorstream.cpp
@ -309,6 +306,8 @@ set(toolkit_SRCS
toolkit/tfile.cpp
toolkit/tfilestream.cpp
toolkit/tdebug.cpp
toolkit/tpicture.cpp
toolkit/tpicturemap.cpp
toolkit/tpropertymap.cpp
toolkit/trefcounter.cpp
toolkit/tdebuglistener.cpp

View File

@ -31,14 +31,16 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevector.h>
#include <tstring.h>
#include <tdebug.h>
#include <tagunion.h>
#include <id3v1tag.h>
#include <id3v2header.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include <memory>
#include "tbytevector.h"
#include "tstring.h"
#include "tdebug.h"
#include "tagunion.h"
#include "id3v1tag.h"
#include "id3v2header.h"
#include "tpropertymap.h"
#include "tagutils.h"
#include "apefile.h"
#include "apetag.h"
@ -56,42 +58,33 @@ class APE::File::FilePrivate {
FilePrivate() : APELocation(-1),
APESize(0),
ID3v1Location(-1),
ID3v2Header(nullptr),
ID3v2Location(-1),
ID3v2Size(0),
properties(nullptr) {}
ID3v2Size(0) {}
~FilePrivate() {
delete ID3v2Header;
delete properties;
}
long long APELocation;
long long APESize;
long APELocation;
long APESize;
long long ID3v1Location;
long ID3v1Location;
std::unique_ptr<ID3v2::Header> ID3v2Header;
long long ID3v2Location;
long long ID3v2Size;
ID3v2::Header *ID3v2Header;
long ID3v2Location;
long ID3v2Size;
DoubleTagUnion tag;
TagUnion tag;
AudioProperties *properties;
std::unique_ptr<AudioProperties> properties;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool APE::File::isSupported(IOStream *) {
bool APE::File::isSupported(IOStream *stream) {
// An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede.
// FIXME:
//const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
//return (buffer.find("MAC ") >= 0);
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
return (buffer.find("MAC ") != ByteVector::npos());
return false;
}
////////////////////////////////////////////////////////////////////////////////
@ -120,14 +113,6 @@ Strawberry_TagLib::TagLib::Tag *APE::File::tag() const {
return &d->tag;
}
PropertyMap APE::File::properties() const {
return d->tag.properties();
}
void APE::File::removeUnsupportedProperties(const StringList &properties) {
d->tag.removeUnsupportedProperties(properties);
}
PropertyMap APE::File::setProperties(const PropertyMap &properties) {
if (ID3v1Tag())
@ -138,7 +123,7 @@ PropertyMap APE::File::setProperties(const PropertyMap &properties) {
}
APE::AudioProperties *APE::File::audioProperties() const {
return d->properties;
return d->properties.get();
}
bool APE::File::save() {
@ -255,7 +240,7 @@ void APE::File::read(bool readProperties) {
if (d->ID3v2Location >= 0) {
seek(d->ID3v2Location);
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
d->ID3v2Header.reset(new ID3v2::Header(readBlock(ID3v2::Header::size())));
d->ID3v2Size = d->ID3v2Header->completeTagSize();
}
@ -283,7 +268,7 @@ void APE::File::read(bool readProperties) {
if (readProperties) {
long streamLength;
long long streamLength;
if (d->APELocation >= 0)
streamLength = d->APELocation;
@ -300,7 +285,7 @@ void APE::File::read(bool readProperties) {
seek(0);
}
d->properties = new AudioProperties(this, streamLength);
d->properties.reset(new AudioProperties(this, streamLength));
}
}

View File

@ -107,36 +107,25 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
/*!
* Destroys this instance of the File.
*/
virtual ~File();
~File() override;
/*!
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag or a combination of the two.
*/
virtual Strawberry_TagLib::TagLib::Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
* If the file contains both an APE and an ID3v1 tag, only APE will be converted to the PropertyMap.
*/
PropertyMap properties() const;
/*!
* Removes unsupported properties. Forwards to the actual Tag's removeUnsupportedProperties() function.
*/
void removeUnsupportedProperties(const StringList &properties);
Strawberry_TagLib::TagLib::Tag *tag() const override;
/*!
* Implements the unified property interface -- import function.
* Creates an APEv2 tag if necessary.
* A potentially existing ID3v1 tag will be updated as well.
*/
PropertyMap setProperties(const PropertyMap &);
PropertyMap setProperties(const PropertyMap&) override;
/*!
* Returns the APE::AudioProperties for this file.
* If no audio properties were read then this will return a null pointer.
*/
virtual AudioProperties *audioProperties() const;
AudioProperties *audioProperties() const override;
/*!
* Saves the file.
@ -144,7 +133,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::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();
bool save() override;
/*!
* Returns a pointer to the ID3v1 tag of the file.
@ -210,7 +199,7 @@ class TAGLIB_EXPORT File : public Strawberry_TagLib::TagLib::File {
static bool isSupported(IOStream *stream);
private:
explicit File(const File &);
File(const File &);
File &operator=(const File &);
void read(bool readProperties);

View File

@ -27,8 +27,8 @@
#include <iostream>
#include <bitset>
#include <tstring.h>
#include <tdebug.h>
#include "tstring.h"
#include "tdebug.h"
#include "apefooter.h"
@ -155,19 +155,19 @@ void APE::Footer::parse(const ByteVector &data) {
// Read the version number
d->version = data.toUInt(8, false);
d->version = data.toUInt32LE(8);
// Read the tag size
d->tagSize = data.toUInt(12, false);
d->tagSize = data.toUInt32LE(12);
// Read the item count
d->itemCount = data.toUInt(16, false);
d->itemCount = data.toUInt32LE(16);
// Read the flags
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false)));
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt32LE(20)));
d->headerPresent = flags[31];
d->footerPresent = !flags[30];
@ -186,15 +186,15 @@ ByteVector APE::Footer::render(bool isHeader) const {
// add the version number -- we always render a 2.000 tag regardless of what
// the tag originally was.
v.append(ByteVector::fromUInt(2000, false));
v.append(ByteVector::fromUInt32LE(2000));
// add the tag size
v.append(ByteVector::fromUInt(d->tagSize, false));
v.append(ByteVector::fromUInt32LE(d->tagSize));
// add the item count
v.append(ByteVector::fromUInt(d->itemCount, false));
v.append(ByteVector::fromUInt32LE(d->itemCount));
// render and add the flags
@ -204,11 +204,11 @@ ByteVector APE::Footer::render(bool isHeader) const {
flags[30] = false; // footer is always present
flags[29] = isHeader;
v.append(ByteVector::fromUInt(flags.to_ulong(), false));
v.append(ByteVector::fromUInt32LE(flags.to_ulong()));
// add the reserved 64bit
v.append(ByteVector::fromLongLong(0));
v.append(ByteVector::fromUInt64BE(0));
return v;

View File

@ -161,7 +161,7 @@ class TAGLIB_EXPORT Footer {
ByteVector render(bool isHeader) const;
private:
explicit Footer(const Footer &);
Footer(const Footer &);
Footer &operator=(const Footer &);
class FooterPrivate;

View File

@ -23,17 +23,18 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevectorlist.h>
#include <tdebug.h>
#include <memory>
#include "tbytevectorlist.h"
#include "tdebug.h"
#include "apeitem.h"
using namespace Strawberry_TagLib::TagLib;
using namespace APE;
class APE::Item::ItemPrivate {
public:
ItemPrivate() : type(Text), readOnly(false) {}
struct ItemData {
ItemData() : type(Item::Text), readOnly(false) {}
Item::ItemTypes type;
String key;
@ -42,26 +43,37 @@ class APE::Item::ItemPrivate {
bool readOnly;
};
class APE::Item::ItemPrivate {
public:
ItemPrivate() : data(new ItemData()) {}
std::shared_ptr<ItemData> data;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
APE::Item::Item() : d(new ItemPrivate()) {}
APE::Item::Item(const String &key, const String &value) : d(new ItemPrivate()) {
d->data->key = key;
d->data->text.append(value);
}
APE::Item::Item(const String &key, const StringList &values) : d(new ItemPrivate()) {
d->key = key;
d->text = values;
d->data->key = key;
d->data->text = values;
}
APE::Item::Item(const String &key, const ByteVector &value, bool binary) : d(new ItemPrivate()) {
d->key = key;
d->data->key = key;
if (binary) {
d->type = Binary;
d->value = value;
d->data->type = Binary;
d->data->value = value;
}
else {
d->text.append(value);
d->data->text.append(value);
}
}
@ -88,126 +100,109 @@ void APE::Item::swap(Item &item) {
}
void APE::Item::setReadOnly(bool readOnly) {
d->readOnly = readOnly;
d->data->readOnly = readOnly;
}
bool APE::Item::isReadOnly() const {
return d->readOnly;
return d->data->readOnly;
}
void APE::Item::setType(APE::Item::ItemTypes type) {
d->type = type;
void APE::Item::setType(APE::Item::ItemTypes val) {
d->data->type = val;
}
APE::Item::ItemTypes APE::Item::type() const {
return d->type;
return d->data->type;
}
String APE::Item::key() const {
return d->key;
return d->data->key;
}
ByteVector APE::Item::binaryData() const {
return d->value;
return d->data->value;
}
void APE::Item::setBinaryData(const ByteVector &value) {
d->type = Binary;
d->value = value;
d->text.clear();
d->data->type = Binary;
d->data->value = value;
d->data->text.clear();
}
void APE::Item::setKey(const String &key) {
d->key = key;
d->data->key = key;
}
void APE::Item::setValue(const String &value) {
d->type = Text;
d->text = value;
d->value.clear();
d->data->type = Text;
d->data->text = value;
d->data->value.clear();
}
void APE::Item::setValues(const StringList &value) {
d->type = Text;
d->text = value;
d->value.clear();
d->data->type = Text;
d->data->text = value;
d->data->value.clear();
}
void APE::Item::appendValue(const String &value) {
d->type = Text;
d->text.append(value);
d->value.clear();
d->data->type = Text;
d->data->text.append(value);
d->data->value.clear();
}
void APE::Item::appendValues(const StringList &values) {
d->type = Text;
d->text.append(values);
d->value.clear();
d->data->type = Text;
d->data->text.append(values);
d->data->value.clear();
}
int APE::Item::size() const {
int result = 8 + d->key.size() + 1;
switch (d->type) {
size_t result = 8 + d->data->key.size() + 1;
switch (d->data->type) {
case Text:
if (!d->text.isEmpty()) {
StringList::ConstIterator it = d->text.begin();
if (!d->data->text.isEmpty()) {
StringList::ConstIterator it = d->data->text.begin();
result += it->data(String::UTF8).size();
it++;
for (; it != d->text.end(); ++it)
for (; it != d->data->text.end(); ++it)
result += 1 + it->data(String::UTF8).size();
}
break;
case Binary:
case Locator:
result += d->value.size();
result += d->data->value.size();
break;
}
return result;
}
StringList APE::Item::toStringList() const {
return d->text;
}
StringList APE::Item::values() const {
return d->text;
return d->data->text;
}
String APE::Item::toString() const {
if (d->type == Text && !isEmpty())
return d->text.front();
if (d->data->type == Text && !isEmpty())
return d->data->text.front();
else
return String();
}
bool APE::Item::isEmpty() const {
switch (d->type) {
switch (d->data->type) {
case Text:
if (d->text.isEmpty())
if (d->data->text.isEmpty())
return true;
if (d->text.size() == 1 && d->text.front().isEmpty())
if (d->data->text.size() == 1 && d->data->text.front().isEmpty())
return true;
return false;
case Binary:
case Locator:
return d->value.isEmpty();
return d->data->value.isEmpty();
default:
return false;
}
@ -223,52 +218,51 @@ void APE::Item::parse(const ByteVector &data) {
return;
}
const unsigned int valueLength = data.toUInt(0, false);
const unsigned int flags = data.toUInt(4, false);
const unsigned int valueLength = data.toUInt32LE(0);
const unsigned int flags = data.toUInt32LE(4);
// 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.
d->key = String(&data[8], String::Latin1);
d->data->key = String(&data[8], String::Latin1);
const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength);
const ByteVector value = data.mid(8 + d->data->key.size() + 1, valueLength);
setReadOnly(flags & 1);
setType(ItemTypes((flags >> 1) & 3));
if (Text == d->type)
d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
if (Text == d->data->type)
d->data->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
else
d->value = value;
d->data->value = value;
}
ByteVector APE::Item::render() const {
ByteVector data;
unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
unsigned int flags = ((d->data->readOnly) ? 1 : 0) | (d->data->type << 1);
ByteVector value;
if (isEmpty())
return data;
if (d->type == Text) {
StringList::ConstIterator it = d->text.begin();
if (d->data->type == Text) {
StringList::ConstIterator it = d->data->text.begin();
value.append(it->data(String::UTF8));
it++;
for (; it != d->text.end(); ++it) {
for (; it != d->data->text.end(); ++it) {
value.append('\0');
value.append(it->data(String::UTF8));
}
d->value = value;
d->data->value = value;
}
else
value.append(d->value);
value.append(d->data->value);
data.append(ByteVector::fromUInt(value.size(), false));
data.append(ByteVector::fromUInt(flags, false));
data.append(d->key.data(String::Latin1));
data.append(ByteVector::fromUInt32LE(value.size()));
data.append(ByteVector::fromUInt32LE(flags));
data.append(d->data->key.data(String::Latin1));
data.append(ByteVector('\0'));
data.append(value);

View File

@ -57,6 +57,11 @@ class TAGLIB_EXPORT Item {
*/
explicit Item();
/*!
* Constructs a text item with \a key and \a values.
*/
explicit Item(const String &key, const String &values);
/*!
* Constructs a text item with \a key and \a values.
*/
@ -71,7 +76,7 @@ class TAGLIB_EXPORT Item {
/*!
* Construct an item as a copy of \a item.
*/
explicit Item(const Item &item);
Item(const Item &item);
/*!
* Destroys the item.
@ -148,7 +153,6 @@ class TAGLIB_EXPORT Item {
* If the data type is not \a Text, always returns an empty String.
*/
String toString() const;
StringList toStringList() const;
/*!
* Returns the list of text values. If the data type is not \a Text, always returns an empty StringList.

View File

@ -27,9 +27,9 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include <bitset>
#include "tstring.h"
#include "tdebug.h"
#include "id3v2tag.h"
#include "apeproperties.h"
#include "apefile.h"
@ -40,13 +40,13 @@ using namespace Strawberry_TagLib::TagLib;
class APE::AudioProperties::AudioPropertiesPrivate {
public:
AudioPropertiesPrivate() : length(0),
bitrate(0),
sampleRate(0),
channels(0),
version(0),
bitsPerSample(0),
sampleFrames(0) {}
explicit AudioPropertiesPrivate() : length(0),
bitrate(0),
sampleRate(0),
channels(0),
version(0),
bitsPerSample(0),
sampleFrames(0) {}
int length;
int bitrate;
@ -61,7 +61,7 @@ class APE::AudioProperties::AudioPropertiesPrivate {
// public members
////////////////////////////////////////////////////////////////////////////////
APE::AudioProperties::AudioProperties(File *file, long streamLength, ReadStyle style) : Strawberry_TagLib::TagLib::AudioProperties(style), d(new AudioPropertiesPrivate()) {
APE::AudioProperties::AudioProperties(File *file, long long streamLength, ReadStyle) : Strawberry_TagLib::TagLib::AudioProperties(), d(new AudioPropertiesPrivate()) {
read(file, streamLength);
}
@ -110,14 +110,14 @@ int headerVersion(const ByteVector &header) {
if (header.size() < 6 || !header.startsWith("MAC "))
return -1;
return header.toUShort(4, false);
return header.toUInt16LE(4);
}
} // namespace
void APE::AudioProperties::read(File *file, long streamLength) {
void APE::AudioProperties::read(File *file, long long streamLength) {
// First, we assume that the file pointer is set at the first descriptor.
long offset = file->tell();
long long offset = file->tell();
int version = headerVersion(file->readBlock(6));
// Next, we look for the descriptor.
@ -157,7 +157,7 @@ void APE::AudioProperties::analyzeCurrent(File *file) {
return;
}
const unsigned int descriptorBytes = descriptor.toUInt(0, false);
const unsigned int descriptorBytes = descriptor.toUInt32LE(0);
if ((descriptorBytes - 52) > 0)
file->seek(descriptorBytes - 52, File::Current);
@ -170,16 +170,16 @@ void APE::AudioProperties::analyzeCurrent(File *file) {
}
// Get the APE info
d->channels = header.toShort(18, false);
d->sampleRate = header.toUInt(20, false);
d->bitsPerSample = header.toShort(16, false);
d->channels = header.toUInt16LE(18);
d->sampleRate = header.toUInt32LE(20);
d->bitsPerSample = header.toUInt16LE(16);
const unsigned int totalFrames = header.toUInt(12, false);
const unsigned int totalFrames = header.toUInt32LE(12);
if (totalFrames == 0)
return;
const unsigned int blocksPerFrame = header.toUInt(4, false);
const unsigned int finalFrameBlocks = header.toUInt(8, false);
const unsigned int blocksPerFrame = header.toUInt32LE(4);
const unsigned int finalFrameBlocks = header.toUInt32LE(8);
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
}
@ -192,13 +192,13 @@ void APE::AudioProperties::analyzeOld(File *file) {
return;
}
const unsigned int totalFrames = header.toUInt(18, false);
const unsigned int totalFrames = header.toUInt32LE(18);
// Fail on 0 length APE files (catches non-finalized APE files)
if (totalFrames == 0)
return;
const short compressionLevel = header.toShort(0, false);
const short compressionLevel = header.toUInt32LE(0);
unsigned int blocksPerFrame;
if (d->version >= 3950)
blocksPerFrame = 73728 * 4;
@ -208,10 +208,10 @@ void APE::AudioProperties::analyzeOld(File *file) {
blocksPerFrame = 9216;
// Get the APE info
d->channels = header.toShort(4, false);
d->sampleRate = header.toUInt(6, false);
d->channels = header.toUInt16LE(4);
d->sampleRate = header.toUInt32LE(6);
const unsigned int finalFrameBlocks = header.toUInt(22, false);
const unsigned int finalFrameBlocks = header.toUInt32LE(22);
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
// Get the bit depth from the RIFF-fmt chunk.
@ -222,6 +222,6 @@ void APE::AudioProperties::analyzeOld(File *file) {
return;
}
d->bitsPerSample = fmt.toShort(26, false);
d->bitsPerSample = fmt.toUInt16LE(26);
}

View File

@ -51,41 +51,41 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro
/*!
* Create an instance of APE::AudioProperties with the data read from the APE::File \a file.
*/
explicit AudioProperties(File *file, long streamLength, ReadStyle style = Average);
explicit AudioProperties(File *file, long long streamLength, ReadStyle style = Average);
/*!
* Destroys this APE::AudioProperties instance.
*/
virtual ~AudioProperties();
~AudioProperties() override;
/*!
* Returns the length of the file in seconds. The length is rounded down to the nearest whole second.
*
* \see lengthInMilliseconds()
*/
virtual int lengthInSeconds() const;
int lengthInSeconds() const override;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
virtual int lengthInMilliseconds() const;
int lengthInMilliseconds() const override;
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
int bitrate() const override;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
int sampleRate() const override;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
int channels() const override;
/*!
* Returns the number of bits per audio sample.
@ -103,10 +103,7 @@ class TAGLIB_EXPORT AudioProperties : public Strawberry_TagLib::TagLib::AudioPro
int version() const;
private:
explicit AudioProperties(const AudioProperties &);
AudioProperties &operator=(const AudioProperties &);
void read(File *file, long streamLength);
void read(File *file, long long streamLength);
void analyzeCurrent(File *file);
void analyzeOld(File *file);

View File

@ -31,12 +31,13 @@
# define WANT_CLASS_INSTANTIATION_OF_MAP (1)
#endif
#include <tfile.h>
#include <tstring.h>
#include <tmap.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include <tutils.h>
#include "tfile.h"
#include "tstring.h"
#include "tmap.h"
#include "tpicturemap.h"
#include "tpropertymap.h"
#include "tdebug.h"
#include "tutils.h"
#include "apetag.h"
#include "apefooter.h"
@ -76,7 +77,7 @@ class APE::Tag::TagPrivate {
TagPrivate() : file(nullptr), footerLocation(0) {}
File *file;
long footerLocation;
long long footerLocation;
Footer footer;
ItemListMap itemListMap;
@ -88,7 +89,7 @@ class APE::Tag::TagPrivate {
APE::Tag::Tag() : d(new TagPrivate()) {}
APE::Tag::Tag(Strawberry_TagLib::TagLib::File *file, long footerLocation) : d(new TagPrivate()) {
APE::Tag::Tag(Strawberry_TagLib::TagLib::File *file, long long footerLocation) : d(new TagPrivate()) {
d->file = file;
d->footerLocation = footerLocation;
@ -160,6 +161,43 @@ unsigned int APE::Tag::track() const {
}
Strawberry_TagLib::TagLib::PictureMap APE::Tag::pictures() const {
PictureMap map;
if (d->itemListMap.contains(FRONT_COVER)) {
Item front = d->itemListMap[FRONT_COVER];
if (Item::Binary == front.type()) {
ByteVector picture = front.binaryData();
const size_t index = picture.find('\0');
if (index < picture.size()) {
ByteVector desc = picture.mid(0, index + 1);
String mime = "image/jpeg";
ByteVector data = picture.mid(index + 1);
Picture p(data, Picture::FrontCover, mime, desc);
map.insert(p);
}
}
}
if (d->itemListMap.contains(BACK_COVER)) {
Item back = d->itemListMap[BACK_COVER];
if (Item::Binary == back.type()) {
ByteVector picture = back.binaryData();
const size_t index = picture.find('\0');
if (index < picture.size()) {
ByteVector desc = picture.mid(0, index + 1);
String mime = "image/jpeg";
ByteVector data = picture.mid(index + 1);
Picture p(data, Picture::BackCover, mime, desc);
map.insert(p);
}
}
}
return PictureMap(map);
}
void APE::Tag::setTitle(const String &s) {
addValue("TITLE", s, true);
}
@ -181,17 +219,72 @@ void APE::Tag::setGenre(const String &s) {
}
void APE::Tag::setYear(unsigned int i) {
if (i == 0)
removeItem("YEAR");
else
addValue("YEAR", String::number(i), true);
}
void APE::Tag::setTrack(unsigned int i) {
if (i == 0)
removeItem("TRACK");
else
addValue("TRACK", String::number(i), true);
}
void APE::Tag::setPictures(const PictureMap &l) {
removeItem(FRONT_COVER);
removeItem(BACK_COVER);
for (PictureMap::ConstIterator pictureMapIt = l.begin(); pictureMapIt != l.end(); ++pictureMapIt) {
Picture::Type type = pictureMapIt->first;
if (Picture::FrontCover != type && Picture::BackCover != type) {
std::cout << "APE: Trying to add a picture with wrong type" << std::endl;
continue;
}
const char *id;
switch (type) {
case Picture::FrontCover:
id = FRONT_COVER;
break;
case Picture::BackCover:
id = BACK_COVER;
break;
default:
id = FRONT_COVER;
break;
}
PictureList list = pictureMapIt->second;
for (PictureList::ConstIterator pictureListIt = list.begin(); pictureListIt != list.end(); ++pictureListIt) {
Picture picture = *pictureListIt;
if (d->itemListMap.contains(id)) {
std::cout << "APE: Already added a picture of type "
<< id
<< " '"
<< picture.description()
<< "' "
<< "and next are being ignored"
<< std::endl;
break;
}
ByteVector data = picture.description().data(String::Latin1).append('\0').append(picture.data());
Item item;
item.setKey(id);
item.setType(Item::Binary);
item.setBinaryData(data);
setItem(item.key(), item);
}
}
}
namespace {
@ -223,7 +316,7 @@ PropertyMap APE::Tag::properties() const {
if (tagName == keyConversions[i][1])
tagName = keyConversions[i][0];
}
properties[tagName].append(it->second.toStringList());
properties[tagName].append(it->second.values());
}
}
return properties;
@ -397,18 +490,18 @@ void APE::Tag::parse(const ByteVector &data) {
if (data.size() < 11)
return;
unsigned int pos = 0;
size_t pos = 0;
for (unsigned int i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
const int nullPos = data.find('\0', pos + 8);
if (nullPos < 0) {
const size_t nullPos = data.find('\0', pos + 8);
if (nullPos == ByteVector::npos()) {
debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing.");
return;
}
const unsigned int keyLength = nullPos - pos - 8;
const unsigned int valLegnth = data.toUInt(pos, false);
const size_t keyLength = nullPos - pos - 8;
const size_t valLegnth = data.toUInt32LE(pos);
if (keyLength >= MinKeyLength && keyLength <= MaxKeyLength && isKeyValid(data.mid(pos + 8, keyLength))) {
APE::Item item;

View File

@ -34,6 +34,9 @@
#include "apeitem.h"
#define FRONT_COVER "COVER ART (FRONT)"
#define BACK_COVER "COVER ART (BACK)"
namespace Strawberry_TagLib {
namespace TagLib {
@ -50,7 +53,7 @@ class Footer;
*
* \see APE::Tag::itemListMap()
*/
typedef Map<const String, Item> ItemListMap;
typedef Map<String, Item> ItemListMap;
//! An APE tag implementation
@ -66,12 +69,12 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
* Create an APE tag and parse the data in \a file with APE footer at
* \a tagOffset.
*/
explicit Tag(Strawberry_TagLib::TagLib::File *file, long footerLocation);
explicit Tag(Strawberry_TagLib::TagLib::File *file, long long footerLocation);
/*!
* Destroys this Tag instance.
*/
virtual ~Tag();
~Tag() override;
/*!
* Renders the in memory values to a ByteVector suitable for writing to the file.
@ -85,21 +88,31 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
// Reimplementations.
virtual String title() const;
virtual String artist() const;
virtual String album() const;
virtual String comment() const;
virtual String genre() const;
virtual unsigned int year() const;
virtual unsigned int track() const;
String title() const override;
String artist() const override;
String album() const override;
String comment() const override;
String genre() const override;
unsigned int year() const override;
unsigned int track() const override;
virtual void setTitle(const String &s);
virtual void setArtist(const String &s);
virtual void setAlbum(const String &s);
virtual void setComment(const String &s);
virtual void setGenre(const String &s);
virtual void setYear(unsigned int i);
virtual void setTrack(unsigned int i);
/**
* @brief pictures
* According to :
* http://www.hydrogenaud.io/forums/index.php?showtopic=40603&st=50&p=504669&#entry504669
* http://git.videolan.org/?p=vlc.git;a=blob;f=modules/meta_engine/taglib.cpp
* @return
*/
PictureMap pictures() const override;
void setTitle(const String &s) override;
void setArtist(const String &s) override;
void setAlbum(const String &s) override;
void setComment(const String &s) override;
void setGenre(const String &s) override;
void setYear(unsigned int i) override;
void setTrack(unsigned int i) override;
void setPictures(const PictureMap &l) override;
/*!
* Implements the unified tag dictionary interface -- export function.
@ -114,9 +127,9 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
* TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST,
* respectively, in order to be compliant with the names used in other formats.
*/
PropertyMap properties() const;
PropertyMap properties() const override;
void removeUnsupportedProperties(const StringList &properties);
void removeUnsupportedProperties(const StringList &properties) override;
/*!
* Implements the unified tag dictionary interface -- import function.
@ -124,7 +137,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
* specification requires keys to have between 2 and 16 printable ASCII characters
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
*/
PropertyMap setProperties(const PropertyMap &);
PropertyMap setProperties(const PropertyMap &) override;
/*!
* Check if the given String is a valid APE tag key.
@ -176,7 +189,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
/*!
* Returns true if the tag does not contain any data.
*/
bool isEmpty() const;
bool isEmpty() const override;
protected:
/*!
@ -190,7 +203,7 @@ class TAGLIB_EXPORT Tag : public Strawberry_TagLib::TagLib::Tag {
void parse(const ByteVector &data);
private:
explicit Tag(const Tag &);
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;

View File

@ -23,9 +23,10 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <taglib.h>
#include <tdebug.h>
#include <trefcounter.h>
#include <memory>
#include "taglib.h"
#include "tdebug.h"
#include "asfattribute.h"
#include "asffile.h"
@ -33,10 +34,11 @@
using namespace Strawberry_TagLib::TagLib;
class ASF::Attribute::AttributePrivate : public RefCounter {