mirror of
https://github.com/taglib/taglib.git
synced 2026-03-28 09:39:52 -04:00
Initial attachments support
This commit is contained in:
committed by
Urs Fleisch
parent
6342f00e8b
commit
6d019a894c
@ -2,40 +2,42 @@
|
||||
#include "matroskafile.h"
|
||||
#include "matroskatag.h"
|
||||
#include "matroskasimpletag.h"
|
||||
#include "matroskaattachments.h"
|
||||
#include "matroskaattachedfile.h"
|
||||
#include "tstring.h"
|
||||
#include "tutils.h"
|
||||
#include "tbytevector.h"
|
||||
#define GREEN_TEXT(s) "[1;32m" s "[0m"
|
||||
#define PRINT_PRETTY(label, value) printf("" GREEN_TEXT(label) ": %s\n", value)
|
||||
#define PRINT_PRETTY(label, value) printf(" " GREEN_TEXT(label) ": %s\n", value)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
if(argc != 2) {
|
||||
printf("Usage: matroskareader FILE\n");
|
||||
return 1;
|
||||
}
|
||||
TagLib::Matroska::File file(argv[1]);
|
||||
if (!file.isValid()) {
|
||||
if(!file.isValid()) {
|
||||
printf("File is not valid\n");
|
||||
return 1;
|
||||
}
|
||||
auto tag = dynamic_cast<TagLib::Matroska::Tag*>(file.tag());
|
||||
if (!tag) {
|
||||
if(!tag) {
|
||||
printf("File has no tag\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const TagLib::Matroska::SimpleTagsList &list = tag->simpleTagsList();
|
||||
printf("Found %i tags:\n\n", list.size());
|
||||
printf("Found %u tag(s):\n", list.size());
|
||||
|
||||
for (TagLib::Matroska::SimpleTag *t : list) {
|
||||
for(TagLib::Matroska::SimpleTag *t : list) {
|
||||
PRINT_PRETTY("Tag Name", t->name().toCString(true));
|
||||
|
||||
TagLib::Matroska::SimpleTagString *tString = nullptr;
|
||||
TagLib::Matroska::SimpleTagBinary *tBinary = nullptr;
|
||||
if ((tString = dynamic_cast<TagLib::Matroska::SimpleTagString*>(t)))
|
||||
if((tString = dynamic_cast<TagLib::Matroska::SimpleTagString*>(t)))
|
||||
PRINT_PRETTY("Tag Value", tString->value().toCString(true));
|
||||
else if ((tBinary = dynamic_cast<TagLib::Matroska::SimpleTagBinary*>(t)))
|
||||
else if((tBinary = dynamic_cast<TagLib::Matroska::SimpleTagBinary*>(t)))
|
||||
PRINT_PRETTY("Tag Value",
|
||||
TagLib::Utils::formatString("Binary with size %i", tBinary->value().size()).toCString(false)
|
||||
);
|
||||
@ -50,5 +52,26 @@ int main(int argc, char *argv[])
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
TagLib::Matroska::Attachments *attachments = file.attachments();
|
||||
if(attachments) {
|
||||
const TagLib::Matroska::Attachments::AttachedFileList &list = attachments->attachedFileList();
|
||||
printf("Found %u attachment(s)\n", list.size());
|
||||
for(auto attachedFile : list) {
|
||||
PRINT_PRETTY("Filename", attachedFile->fileName().toCString(true));
|
||||
const TagLib::String &description = attachedFile->description();
|
||||
PRINT_PRETTY("Description", !description.isEmpty() ? description.toCString(true) : "None");
|
||||
const TagLib::String &mediaType = attachedFile->mediaType();
|
||||
PRINT_PRETTY("Media Type", !mediaType.isEmpty() ? mediaType.toCString(false) : "None");
|
||||
PRINT_PRETTY("Data Size",
|
||||
TagLib::Utils::formatString("%u byte(s)",attachedFile->data().size()).toCString(false)
|
||||
);
|
||||
PRINT_PRETTY("UID",
|
||||
TagLib::Utils::formatString("%llu",attachedFile->uid()).toCString(false)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("File has no attachments\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2,17 +2,20 @@
|
||||
#include "matroskafile.h"
|
||||
#include "matroskatag.h"
|
||||
#include "matroskasimpletag.h"
|
||||
#include "matroskaattachments.h"
|
||||
#include "matroskaattachedfile.h"
|
||||
#include "tfilestream.h"
|
||||
#include "tstring.h"
|
||||
#include "tutils.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
printf("Usage: matroskawriter FILE\n");
|
||||
if(argc != 3) {
|
||||
printf("Usage: matroskawriter FILE ARTWORK\n");
|
||||
return 1;
|
||||
}
|
||||
TagLib::Matroska::File file(argv[1]);
|
||||
if (!file.isValid()) {
|
||||
if(!file.isValid()) {
|
||||
printf("File is not valid\n");
|
||||
return 1;
|
||||
}
|
||||
@ -31,6 +34,19 @@ int main(int argc, char *argv[])
|
||||
simpleTag->setTargetTypeValue(TagLib::Matroska::SimpleTag::TargetTypeValue::Album);
|
||||
simpleTag->setValue("Test Value 2");
|
||||
tag->addSimpleTag(simpleTag);
|
||||
tag->setTitle("Test title");
|
||||
tag->setArtist("Test artist");
|
||||
tag->setYear(1969);
|
||||
|
||||
TagLib::FileStream image(argv[2]);
|
||||
auto data = image.readBlock(image.length());
|
||||
auto attachments = file.attachments(true);
|
||||
auto attachedFile = new TagLib::Matroska::AttachedFile();
|
||||
attachedFile->setFileName("cover.jpg");
|
||||
attachedFile->setMediaType("image/jpeg");
|
||||
attachedFile->setData(data);
|
||||
//attachedFile->setUID(5081000385627515072ull);
|
||||
attachments->addAttachedFile(attachedFile);
|
||||
|
||||
file.save();
|
||||
|
||||
|
||||
@ -92,9 +92,12 @@ set(tag_PUBLIC_HDRS
|
||||
toolkit/tpropertymap.h
|
||||
toolkit/tdebuglistener.h
|
||||
toolkit/tversionnumber.h
|
||||
matroska/matroskaattachedfile.h
|
||||
matroska/matroskaattachments.h
|
||||
matroska/matroskafile.h
|
||||
matroska/matroskatag.h
|
||||
matroska/matroskasimpletag.h
|
||||
matroska/matroskaelement.h
|
||||
mpeg/mpegfile.h
|
||||
mpeg/mpegproperties.h
|
||||
mpeg/mpegheader.h
|
||||
@ -227,8 +230,10 @@ if(WITH_SHORTEN)
|
||||
endif()
|
||||
|
||||
set(tag_PRIVATE_HDRS
|
||||
matroska/ebml/ebmlbinaryelement.h
|
||||
matroska/ebml/ebmlelement.h
|
||||
matroska/ebml/ebmlmasterelement.h
|
||||
matroska/ebml/ebmlmkattachments.h
|
||||
matroska/ebml/ebmlmksegment.h
|
||||
matroska/ebml/ebmlmktags.h
|
||||
matroska/ebml/ebmlstringelement.h
|
||||
@ -239,14 +244,19 @@ set(tag_PRIVATE_HDRS
|
||||
set(tag_HDRS ${tag_PUBLIC_HDRS} ${tag_PRIVATE_HDRS})
|
||||
|
||||
set(matroska_SRCS
|
||||
matroska/matroskaattachedfile.cpp
|
||||
matroska/matroskaattachments.cpp
|
||||
matroska/matroskaelement.cpp
|
||||
matroska/matroskafile.cpp
|
||||
matroska/matroskasimpletag.cpp
|
||||
matroska/matroskatag.cpp
|
||||
)
|
||||
|
||||
set(ebml_SRCS
|
||||
matroska/ebml/ebmlbinaryelement.cpp
|
||||
matroska/ebml/ebmlelement.cpp
|
||||
matroska/ebml/ebmlmasterelement.cpp
|
||||
matroska/ebml/ebmlmkattachments.cpp
|
||||
matroska/ebml/ebmlmksegment.cpp
|
||||
matroska/ebml/ebmlmktags.cpp
|
||||
matroska/ebml/ebmlstringelement.cpp
|
||||
|
||||
46
taglib/matroska/ebml/ebmlbinaryelement.cpp
Normal file
46
taglib/matroska/ebml/ebmlbinaryelement.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/***************************************************************************
|
||||
* 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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlbinaryelement.h"
|
||||
#include "tfile.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tdebug.h"
|
||||
#include <string>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
bool EBML::BinaryElement::read(TagLib::File &file)
|
||||
{
|
||||
value = file.readBlock(dataSize);
|
||||
if(value.size() != dataSize) {
|
||||
debug("Failed to read binary element");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteVector EBML::BinaryElement::render()
|
||||
{
|
||||
ByteVector buffer = renderId();
|
||||
dataSize = value.size();
|
||||
buffer.append(renderVINT(dataSize, 0));
|
||||
buffer.append(value);
|
||||
return buffer;
|
||||
}
|
||||
54
taglib/matroska/ebml/ebmlbinaryelement.h
Normal file
54
taglib/matroska/ebml/ebmlbinaryelement.h
Normal file
@ -0,0 +1,54 @@
|
||||
/***************************************************************************
|
||||
* 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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_EBMLBINARYELEMENT_H
|
||||
#define TAGLIB_EBMLBINARYELEMENT_H
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
#include <cstdint>
|
||||
#include "ebmlelement.h"
|
||||
#include "ebmlutils.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
namespace TagLib {
|
||||
class File;
|
||||
namespace EBML {
|
||||
class BinaryElement : public Element
|
||||
{
|
||||
public:
|
||||
BinaryElement(Id id, int sizeLength, offset_t dataSize)
|
||||
: Element(id, sizeLength, dataSize)
|
||||
{}
|
||||
BinaryElement(Id id)
|
||||
: Element(id, 0, 0)
|
||||
{}
|
||||
const ByteVector& getValue() const { return value; }
|
||||
void setValue(const ByteVector &value) { this->value = value; }
|
||||
bool read(File &file) override;
|
||||
ByteVector render() override;
|
||||
|
||||
private:
|
||||
ByteVector value;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@ -20,8 +20,10 @@
|
||||
|
||||
#include "ebmlelement.h"
|
||||
#include "ebmlmasterelement.h"
|
||||
#include "ebmlbinaryelement.h"
|
||||
#include "ebmlmksegment.h"
|
||||
#include "ebmlmktags.h"
|
||||
#include "ebmlmkattachments.h"
|
||||
#include "ebmlstringelement.h"
|
||||
#include "ebmluintelement.h"
|
||||
#include "ebmlutils.h"
|
||||
@ -36,15 +38,16 @@ using namespace TagLib;
|
||||
EBML::Element* EBML::Element::factory(File &file)
|
||||
{
|
||||
// Get the element ID
|
||||
offset_t offset = file.tell();
|
||||
Id id = readId(file);
|
||||
if (!id) {
|
||||
if(!id) {
|
||||
debug("Failed to parse EMBL ElementID");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get the size length and data length
|
||||
const auto& [sizeLength, dataSize] = readVINT<offset_t>(file);
|
||||
if (!sizeLength)
|
||||
if(!sizeLength)
|
||||
return nullptr;
|
||||
|
||||
// Return the subclass
|
||||
@ -53,26 +56,37 @@ EBML::Element* EBML::Element::factory(File &file)
|
||||
return new Element(id, sizeLength, dataSize);
|
||||
|
||||
case ElementIDs::MkSegment:
|
||||
return new MkSegment(sizeLength, dataSize);
|
||||
return new MkSegment(sizeLength, dataSize, offset);
|
||||
|
||||
case ElementIDs::MkTags:
|
||||
return new MkTags(sizeLength, dataSize);
|
||||
return new MkTags(sizeLength, dataSize, offset);
|
||||
|
||||
case ElementIDs::MkAttachments:
|
||||
return new MkAttachments(sizeLength, dataSize, offset);
|
||||
|
||||
case ElementIDs::MkTag:
|
||||
case ElementIDs::MkTagTargets:
|
||||
case ElementIDs::MkSimpleTag:
|
||||
return new MasterElement(id, sizeLength, dataSize);
|
||||
case ElementIDs::MkAttachedFile:
|
||||
return new MasterElement(id, sizeLength, dataSize, offset);
|
||||
|
||||
case ElementIDs::MkTagName:
|
||||
case ElementIDs::MkTagString:
|
||||
case ElementIDs::MkAttachedFileName:
|
||||
case ElementIDs::MkAttachedFileDescription:
|
||||
return new UTF8StringElement(id, sizeLength, dataSize);
|
||||
|
||||
case ElementIDs::MkTagLanguage:
|
||||
case ElementIDs::MkAttachedFileMediaType:
|
||||
return new Latin1StringElement(id, sizeLength, dataSize);
|
||||
|
||||
case ElementIDs::MkTagTargetTypeValue:
|
||||
case ElementIDs::MkAttachedFileUID:
|
||||
return new UIntElement(id, sizeLength, dataSize);
|
||||
|
||||
case ElementIDs::MkAttachedFileData:
|
||||
return new BinaryElement(id, sizeLength, dataSize);
|
||||
|
||||
default:
|
||||
return new Element(id, sizeLength, dataSize);
|
||||
}
|
||||
@ -83,16 +97,16 @@ EBML::Element* EBML::Element::factory(File &file)
|
||||
EBML::Element::Id EBML::Element::readId(File &file)
|
||||
{
|
||||
auto buffer = file.readBlock(1);
|
||||
if (buffer.size() != 1) {
|
||||
if(buffer.size() != 1) {
|
||||
debug("Failed to read VINT size");
|
||||
return 0;
|
||||
}
|
||||
unsigned int nb_bytes = VINTSizeLength<4>(*buffer.begin());
|
||||
if (!nb_bytes)
|
||||
if(!nb_bytes)
|
||||
return 0;
|
||||
if (nb_bytes > 1)
|
||||
if(nb_bytes > 1)
|
||||
buffer.append(file.readBlock(nb_bytes - 1));
|
||||
if (buffer.size() != nb_bytes) {
|
||||
if(buffer.size() != nb_bytes) {
|
||||
debug("Failed to read VINT data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
|
||||
#include "tfile.h"
|
||||
#include "tutils.h"
|
||||
//#include "ebmlutils.h"
|
||||
#include "taglib.h"
|
||||
|
||||
namespace TagLib {
|
||||
@ -37,7 +36,6 @@ namespace TagLib {
|
||||
: id(id), sizeLength(sizeLength), dataSize(dataSize)
|
||||
{}
|
||||
virtual ~Element() = default;
|
||||
virtual bool isMaster() const { return false; }
|
||||
virtual bool read(File &file) {
|
||||
skipData(file);
|
||||
return true;
|
||||
@ -59,22 +57,29 @@ namespace TagLib {
|
||||
};
|
||||
|
||||
namespace ElementIDs {
|
||||
inline constexpr Element::Id EBMLHeader = 0x1A45DFA3;
|
||||
inline constexpr Element::Id MkSegment = 0x18538067;
|
||||
inline constexpr Element::Id MkTags = 0x1254C367;
|
||||
inline constexpr Element::Id MkTag = 0x7373;
|
||||
inline constexpr Element::Id MkTagTargets = 0x63C0;
|
||||
inline constexpr Element::Id MkTagTargetTypeValue = 0x68CA;
|
||||
inline constexpr Element::Id MkSimpleTag = 0x67C8;
|
||||
inline constexpr Element::Id MkTagName = 0x45A3;
|
||||
inline constexpr Element::Id MkTagLanguage = 0x447A;
|
||||
inline constexpr Element::Id MkTagString = 0x4487;
|
||||
inline constexpr Element::Id MkTagsTagLanguage = 0x447A;
|
||||
inline constexpr Element::Id MkTagsLanguageDefault = 0x4484;
|
||||
inline constexpr Element::Id EBMLHeader = 0x1A45DFA3;
|
||||
inline constexpr Element::Id MkSegment = 0x18538067;
|
||||
inline constexpr Element::Id MkTags = 0x1254C367;
|
||||
inline constexpr Element::Id MkTag = 0x7373;
|
||||
inline constexpr Element::Id MkTagTargets = 0x63C0;
|
||||
inline constexpr Element::Id MkTagTargetTypeValue = 0x68CA;
|
||||
inline constexpr Element::Id MkSimpleTag = 0x67C8;
|
||||
inline constexpr Element::Id MkTagName = 0x45A3;
|
||||
inline constexpr Element::Id MkTagLanguage = 0x447A;
|
||||
inline constexpr Element::Id MkTagString = 0x4487;
|
||||
inline constexpr Element::Id MkTagsTagLanguage = 0x447A;
|
||||
inline constexpr Element::Id MkTagsLanguageDefault = 0x4484;
|
||||
inline constexpr Element::Id MkAttachments = 0x1941A469;
|
||||
inline constexpr Element::Id MkAttachedFile = 0x61A7;
|
||||
inline constexpr Element::Id MkAttachedFileDescription = 0x467E;
|
||||
inline constexpr Element::Id MkAttachedFileName = 0x466E;
|
||||
inline constexpr Element::Id MkAttachedFileMediaType = 0x4660;
|
||||
inline constexpr Element::Id MkAttachedFileData = 0x465C;
|
||||
inline constexpr Element::Id MkAttachedFileUID = 0x46AE;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -30,7 +30,7 @@ using namespace TagLib;
|
||||
|
||||
EBML::MasterElement::~MasterElement()
|
||||
{
|
||||
for (auto element : elements)
|
||||
for(auto element : elements)
|
||||
delete element;
|
||||
}
|
||||
|
||||
@ -38,8 +38,8 @@ bool EBML::MasterElement::read(File &file)
|
||||
{
|
||||
offset_t maxOffset = file.tell() + dataSize;
|
||||
Element *element = nullptr;
|
||||
while ((element = findNextElement(file, maxOffset))) {
|
||||
if (!element->read(file))
|
||||
while((element = findNextElement(file, maxOffset))) {
|
||||
if(!element->read(file))
|
||||
return false;
|
||||
elements.append(element);
|
||||
}
|
||||
@ -50,7 +50,7 @@ ByteVector EBML::MasterElement::render()
|
||||
{
|
||||
ByteVector buffer = renderId();
|
||||
ByteVector data;
|
||||
for (auto element : elements)
|
||||
for(auto element : elements)
|
||||
data.append(element->render());
|
||||
dataSize = data.size();
|
||||
buffer.append(renderVINT(dataSize, 0));
|
||||
|
||||
@ -33,15 +33,16 @@ namespace TagLib {
|
||||
class MasterElement : public Element
|
||||
{
|
||||
public:
|
||||
MasterElement(Id id, int sizeLength, offset_t dataSize)
|
||||
: Element(id, sizeLength, dataSize)
|
||||
MasterElement(Id id, int sizeLength, offset_t dataSize, offset_t offset)
|
||||
: Element(id, sizeLength, dataSize), offset(offset)
|
||||
{}
|
||||
MasterElement(Id id)
|
||||
: Element(id, 0, 0)
|
||||
: Element(id, 0, 0), offset(0)
|
||||
{}
|
||||
~MasterElement() override;
|
||||
virtual bool isMaster() const override { return true; }
|
||||
virtual bool read(File &file) override;
|
||||
offset_t getOffset() const { return offset; }
|
||||
offset_t getSize() const { return headSize() + dataSize; }
|
||||
bool read(File &file) override;
|
||||
ByteVector render() override;
|
||||
void appendElement(Element *element) { elements.append(element); }
|
||||
List<Element*>::Iterator begin () { return elements.begin(); }
|
||||
@ -50,6 +51,7 @@ namespace TagLib {
|
||||
List<Element*>::ConstIterator cend () const { return elements.cend(); }
|
||||
|
||||
protected:
|
||||
offset_t offset;
|
||||
List<Element*> elements;
|
||||
};
|
||||
|
||||
|
||||
77
taglib/matroska/ebml/ebmlmkattachments.cpp
Normal file
77
taglib/matroska/ebml/ebmlmkattachments.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/***************************************************************************
|
||||
* 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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlmkattachments.h"
|
||||
#include "ebmlstringelement.h"
|
||||
#include "ebmluintelement.h"
|
||||
#include "ebmlbinaryelement.h"
|
||||
#include "matroskaattachments.h"
|
||||
#include "matroskaattachedfile.h"
|
||||
#include "tdebug.h"
|
||||
#include "tutils.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
Matroska::Attachments* EBML::MkAttachments::parse()
|
||||
{
|
||||
auto attachments = new Matroska::Attachments();
|
||||
attachments->setOffset(offset);
|
||||
attachments->setSize(getSize());
|
||||
|
||||
for(auto element : elements) {
|
||||
if(element->getId() != ElementIDs::MkAttachedFile)
|
||||
continue;
|
||||
|
||||
const String *filename = nullptr;
|
||||
const String *description = nullptr;
|
||||
const String *mediaType = nullptr;
|
||||
const ByteVector *data = nullptr;
|
||||
Matroska::AttachedFile::UID uid = 0;
|
||||
auto attachedFile = static_cast<MasterElement*>(element);
|
||||
for(auto attachedFileChild : *attachedFile) {
|
||||
Id id = attachedFileChild->getId();
|
||||
if(id == ElementIDs::MkAttachedFileName)
|
||||
filename = &(static_cast<UTF8StringElement*>(attachedFileChild)->getValue());
|
||||
else if(id == ElementIDs::MkAttachedFileData)
|
||||
data = &(static_cast<BinaryElement*>(attachedFileChild)->getValue());
|
||||
else if(id == ElementIDs::MkAttachedFileDescription)
|
||||
description = &(static_cast<UTF8StringElement*>(attachedFileChild)->getValue());
|
||||
else if(id == ElementIDs::MkAttachedFileMediaType)
|
||||
mediaType = &(static_cast<Latin1StringElement*>(attachedFileChild)->getValue());
|
||||
else if(id == ElementIDs::MkAttachedFileUID)
|
||||
uid = static_cast<UIntElement*>(attachedFileChild)->getValue();
|
||||
}
|
||||
if(!(filename && data))
|
||||
continue;
|
||||
|
||||
auto file = new Matroska::AttachedFile();
|
||||
file->setFileName(*filename);
|
||||
file->setData(*data);
|
||||
if(description)
|
||||
file->setDescription(*description);
|
||||
if(mediaType)
|
||||
file->setMediaType(*mediaType);
|
||||
if(uid)
|
||||
file->setUID(uid);
|
||||
|
||||
attachments->addAttachedFile(file);
|
||||
}
|
||||
return attachments;
|
||||
}
|
||||
49
taglib/matroska/ebml/ebmlmkattachments.h
Normal file
49
taglib/matroska/ebml/ebmlmkattachments.h
Normal file
@ -0,0 +1,49 @@
|
||||
/***************************************************************************
|
||||
* 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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlmasterelement.h"
|
||||
#include "ebmlutils.h"
|
||||
#include "taglib.h"
|
||||
|
||||
#ifndef TAGLIB_EBMLMKATTACHMENTS_H
|
||||
#define TAGLIB_EBMLMKATTACHMENTS_H
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
namespace TagLib {
|
||||
namespace Matroska {
|
||||
class Attachments;
|
||||
}
|
||||
namespace EBML {
|
||||
class MkAttachments : public MasterElement
|
||||
{
|
||||
public:
|
||||
MkAttachments(int sizeLength, offset_t dataSize, offset_t offset)
|
||||
: MasterElement(ElementIDs::MkAttachments, sizeLength, dataSize, offset)
|
||||
{}
|
||||
MkAttachments()
|
||||
: MasterElement(ElementIDs::MkAttachments, 0, 0, 0)
|
||||
{}
|
||||
Matroska::Attachments* parse();
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@ -20,9 +20,11 @@
|
||||
|
||||
#include "ebmlmksegment.h"
|
||||
#include "ebmlmktags.h"
|
||||
#include "ebmlmkattachments.h"
|
||||
#include "ebmlutils.h"
|
||||
#include "matroskafile.h"
|
||||
#include "matroskatag.h"
|
||||
#include "matroskaattachments.h"
|
||||
#include "tutils.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tdebug.h"
|
||||
@ -32,26 +34,40 @@ using namespace TagLib;
|
||||
EBML::MkSegment::~MkSegment()
|
||||
{
|
||||
delete tags;
|
||||
delete attachments;
|
||||
}
|
||||
|
||||
bool EBML::MkSegment::read(File &file)
|
||||
{
|
||||
offset_t maxOffset = file.tell() + dataSize;
|
||||
tags = static_cast<MkTags*>(findElement(file, ElementIDs::MkTags, maxOffset));
|
||||
if (tags) {
|
||||
offset_t tagsHeadSize = tags->headSize();
|
||||
tagsOffset = file.tell() - tagsHeadSize;
|
||||
tagsOriginalSize = tagsHeadSize + tags->getDataSize();
|
||||
if (!tags->read(file))
|
||||
return false;
|
||||
EBML::Element *element = nullptr;
|
||||
|
||||
while((element = findNextElement(file, maxOffset))) {
|
||||
Id id = element->getId();
|
||||
if(id == ElementIDs::MkTags) {
|
||||
tags = static_cast<MkTags*>(element);
|
||||
if(!tags->read(file))
|
||||
return false;
|
||||
}
|
||||
else if(id == ElementIDs::MkAttachments) {
|
||||
attachments = static_cast<MkAttachments*>(element);
|
||||
if(!attachments->read(file))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
element->skipData(file);
|
||||
delete element;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::tuple<Matroska::Tag*, offset_t, offset_t> EBML::MkSegment::parseTag()
|
||||
Matroska::Tag* EBML::MkSegment::parseTag()
|
||||
{
|
||||
if (tags)
|
||||
return {tags->parse(), tagsOffset, tagsOriginalSize};
|
||||
else
|
||||
return {nullptr, 0, 0};
|
||||
return tags ? tags->parse() : nullptr;
|
||||
}
|
||||
|
||||
Matroska::Attachments* EBML::MkSegment::parseAttachments()
|
||||
{
|
||||
return attachments ? attachments->parse() : nullptr;
|
||||
}
|
||||
|
||||
@ -29,24 +29,25 @@
|
||||
namespace TagLib {
|
||||
namespace Matroska {
|
||||
class Tag;
|
||||
class Attachments;
|
||||
}
|
||||
namespace EBML {
|
||||
class Tags;
|
||||
class MkTags;
|
||||
class MkAttachments;
|
||||
class MkSegment : public MasterElement
|
||||
{
|
||||
public:
|
||||
MkSegment(int sizeLength, offset_t dataSize)
|
||||
: MasterElement(ElementIDs::MkSegment, sizeLength, dataSize)
|
||||
MkSegment(int sizeLength, offset_t dataSize, offset_t offset)
|
||||
: MasterElement(ElementIDs::MkSegment, sizeLength, dataSize, offset)
|
||||
{}
|
||||
~MkSegment() override;
|
||||
bool read(File &file) override;
|
||||
std::tuple<Matroska::Tag*, offset_t, offset_t> parseTag();
|
||||
Matroska::Tag* parseTag();
|
||||
Matroska::Attachments* parseAttachments();
|
||||
|
||||
private:
|
||||
MkTags *tags = nullptr;
|
||||
offset_t tagsOffset = 0;
|
||||
offset_t tagsOriginalSize = 0;
|
||||
MkAttachments *attachments = nullptr;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@ -34,30 +34,32 @@ using namespace TagLib;
|
||||
Matroska::Tag* EBML::MkTags::parse()
|
||||
{
|
||||
auto mTag = new Matroska::Tag();
|
||||
mTag->setOffset(offset);
|
||||
mTag->setSize(getSize());
|
||||
|
||||
// Loop through each <Tag> element
|
||||
for (auto tagsChild : elements) {
|
||||
if (tagsChild->getId() != ElementIDs::MkTag)
|
||||
for(auto tagsChild : elements) {
|
||||
if(tagsChild->getId() != ElementIDs::MkTag)
|
||||
continue;
|
||||
auto tag = static_cast<MasterElement*>(tagsChild);
|
||||
List<MasterElement*> simpleTags;
|
||||
MasterElement *targets = nullptr;
|
||||
|
||||
// Identify the <Targets> element and the <SimpleTag> elements
|
||||
for (auto tagChild : *tag) {
|
||||
for(auto tagChild : *tag) {
|
||||
Id tagChildId = tagChild->getId();
|
||||
if (!targets && tagChildId == ElementIDs::MkTagTargets)
|
||||
if(!targets && tagChildId == ElementIDs::MkTagTargets)
|
||||
targets = static_cast<MasterElement*>(tagChild);
|
||||
else if (tagChildId == ElementIDs::MkSimpleTag)
|
||||
else if(tagChildId == ElementIDs::MkSimpleTag)
|
||||
simpleTags.append(static_cast<MasterElement*>(tagChild));
|
||||
}
|
||||
|
||||
// Parse the <Targets> element
|
||||
Matroska::SimpleTag::TargetTypeValue targetTypeValue = Matroska::SimpleTag::TargetTypeValue::None;
|
||||
if (targets) {
|
||||
for (auto targetsChild : *targets) {
|
||||
if(targets) {
|
||||
for(auto targetsChild : *targets) {
|
||||
Id id = targetsChild->getId();
|
||||
if (id == ElementIDs::MkTagTargetTypeValue
|
||||
if(id == ElementIDs::MkTagTargetTypeValue
|
||||
&& targetTypeValue == Matroska::SimpleTag::TargetTypeValue::None) {
|
||||
targetTypeValue = static_cast<Matroska::SimpleTag::TargetTypeValue>(
|
||||
static_cast<UIntElement*>(targetsChild)->getValue()
|
||||
@ -67,43 +69,43 @@ Matroska::Tag* EBML::MkTags::parse()
|
||||
}
|
||||
|
||||
// Parse each <SimpleTag>
|
||||
for (auto simpleTag : simpleTags) {
|
||||
for(auto simpleTag : simpleTags) {
|
||||
const String *tagName = nullptr;
|
||||
const String *tagValueString = nullptr;
|
||||
const ByteVector *tagValueBinary = nullptr;
|
||||
const String *language = nullptr;
|
||||
bool defaultLanguageFlag = true;
|
||||
|
||||
for (auto simpleTagChild : *simpleTag) {
|
||||
for(auto simpleTagChild : *simpleTag) {
|
||||
Id id = simpleTagChild->getId();
|
||||
if (id == ElementIDs::MkTagName && !tagName)
|
||||
if(id == ElementIDs::MkTagName && !tagName)
|
||||
tagName = &(static_cast<UTF8StringElement*>(simpleTagChild)->getValue());
|
||||
else if (id == ElementIDs::MkTagString && !tagValueString)
|
||||
else if(id == ElementIDs::MkTagString && !tagValueString)
|
||||
tagValueString = &(static_cast<UTF8StringElement*>(simpleTagChild)->getValue());
|
||||
else if (id == ElementIDs::MkTagsTagLanguage && !language)
|
||||
else if(id == ElementIDs::MkTagsTagLanguage && !language)
|
||||
language = &(static_cast<Latin1StringElement*>(simpleTagChild)->getValue());
|
||||
else if (id == ElementIDs::MkTagsLanguageDefault)
|
||||
else if(id == ElementIDs::MkTagsLanguageDefault)
|
||||
defaultLanguageFlag = static_cast<UIntElement*>(simpleTagChild)->getValue() ? true : false;
|
||||
}
|
||||
if (!tagName || (tagValueString && tagValueBinary) || (!tagValueString && !tagValueBinary))
|
||||
if(!tagName || (tagValueString && tagValueBinary) || (!tagValueString && !tagValueBinary))
|
||||
continue;
|
||||
|
||||
// Create a Simple Tag object and add it to the Tag object
|
||||
Matroska::SimpleTag *sTag = nullptr;
|
||||
if (tagValueString) {
|
||||
if(tagValueString) {
|
||||
auto sTagString = new Matroska::SimpleTagString();
|
||||
sTagString->setTargetTypeValue(targetTypeValue);
|
||||
sTagString->setValue(*tagValueString);
|
||||
sTag = sTagString;
|
||||
}
|
||||
else if (tagValueBinary) {
|
||||
else if(tagValueBinary) {
|
||||
auto sTagBinary = new Matroska::SimpleTagBinary();
|
||||
sTagBinary->setTargetTypeValue(targetTypeValue);
|
||||
sTagBinary->setValue(*tagValueBinary);
|
||||
sTag = sTagBinary;
|
||||
}
|
||||
sTag->setName(*tagName);
|
||||
if (language)
|
||||
if(language)
|
||||
sTag->setLanguage(*language);
|
||||
sTag->setDefaultLanguageFlag(defaultLanguageFlag);
|
||||
mTag->addSimpleTag(sTag);
|
||||
|
||||
@ -35,11 +35,11 @@ namespace TagLib {
|
||||
class MkTags : public MasterElement
|
||||
{
|
||||
public:
|
||||
MkTags(int sizeLength, offset_t dataSize)
|
||||
: MasterElement(ElementIDs::MkTags, sizeLength, dataSize)
|
||||
MkTags(int sizeLength, offset_t dataSize, offset_t offset)
|
||||
: MasterElement(ElementIDs::MkTags, sizeLength, dataSize, offset)
|
||||
{}
|
||||
MkTags()
|
||||
: MasterElement(ElementIDs::MkTags, 0, 0)
|
||||
: MasterElement(ElementIDs::MkTags, 0, 0, 0)
|
||||
{}
|
||||
//virtual void read(File &file) override;
|
||||
Matroska::Tag* parse();
|
||||
|
||||
@ -31,15 +31,15 @@ template<String::Type t>
|
||||
bool EBML::StringElement<t>::read(TagLib::File &file)
|
||||
{
|
||||
ByteVector buffer = file.readBlock(dataSize);
|
||||
if (buffer.size() != dataSize) {
|
||||
if(buffer.size() != dataSize) {
|
||||
debug("Failed to read string");
|
||||
return false;
|
||||
}
|
||||
|
||||
// The EBML strings aren't supposed to be null-terminated,
|
||||
// but we'll check for it and stip the null terminator if found
|
||||
// but we'll check for it and strip the null terminator if found
|
||||
int nullByte = buffer.find('\0');
|
||||
if (nullByte >= 0)
|
||||
if(nullByte >= 0)
|
||||
buffer = ByteVector(buffer.data(), nullByte);
|
||||
value = String(buffer, t);
|
||||
return true;
|
||||
|
||||
@ -29,22 +29,42 @@ using namespace TagLib;
|
||||
bool EBML::UIntElement::read(TagLib::File &file)
|
||||
{
|
||||
ByteVector buffer = file.readBlock(dataSize);
|
||||
if (buffer.size() != dataSize) {
|
||||
if(buffer.size() != dataSize) {
|
||||
debug("Failed to read EBML Uint element");
|
||||
return false;
|
||||
}
|
||||
value = buffer.toLongLong(true);
|
||||
value = buffer.toULongLong(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteVector EBML::UIntElement::render()
|
||||
{
|
||||
int dataSize = 0;
|
||||
if(value <= 0xFFull)
|
||||
dataSize = 1;
|
||||
else if(value <= 0xFFFFull)
|
||||
dataSize = 2;
|
||||
else if(value <= 0xFFFFFFull)
|
||||
dataSize = 3;
|
||||
else if(value <= 0xFFFFFFFFull)
|
||||
dataSize = 4;
|
||||
else if(value <= 0xFFFFFFFFFFull)
|
||||
dataSize = 5;
|
||||
else if(value <= 0xFFFFFFFFFFFFull)
|
||||
dataSize = 6;
|
||||
else if(value <= 0xFFFFFFFFFFFFFFull)
|
||||
dataSize = 7;
|
||||
else if(value <= 0xFFFFFFFFFFFFFFFFull)
|
||||
dataSize = 8;
|
||||
|
||||
ByteVector buffer = renderId();
|
||||
dataSize = minSize(value);
|
||||
//dataSize = minSize(value);
|
||||
buffer.append(renderVINT(dataSize, 0));
|
||||
uint64_t value = this->value;
|
||||
unsigned long long value = this->value;
|
||||
//debug(Utils::formatString("Writing %llu", value));
|
||||
|
||||
static const auto byteOrder = Utils::systemByteOrder();
|
||||
if (byteOrder == Utils::LittleEndian)
|
||||
if(byteOrder == Utils::LittleEndian)
|
||||
value = Utils::byteSwap((unsigned long long) value);
|
||||
|
||||
buffer.append(ByteVector((char*) &value + (sizeof(value) - dataSize), dataSize));
|
||||
|
||||
@ -38,13 +38,13 @@ namespace TagLib {
|
||||
UIntElement(Id id)
|
||||
: UIntElement(id, 0, 0)
|
||||
{}
|
||||
unsigned int getValue() const { return value; }
|
||||
void setValue(unsigned int value) { this->value = value; }
|
||||
unsigned long long getValue() const { return value; }
|
||||
void setValue(unsigned long long value) { this->value = value; }
|
||||
bool read(File &file) override;
|
||||
ByteVector render() override;
|
||||
|
||||
private:
|
||||
uint64_t value = 0;
|
||||
unsigned long long value = 0;
|
||||
|
||||
//protected:
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <random>
|
||||
#include "ebmlutils.h"
|
||||
#include "ebmlelement.h"
|
||||
#include "tbytevector.h"
|
||||
@ -32,9 +33,9 @@ using namespace TagLib;
|
||||
EBML::Element* EBML::findElement(File &file, EBML::Element::Id id, offset_t maxOffset)
|
||||
{
|
||||
Element *element = nullptr;
|
||||
while (file.tell() < maxOffset) {
|
||||
while(file.tell() < maxOffset) {
|
||||
element = Element::factory(file);
|
||||
if (!element || element->getId() == id)
|
||||
if(!element || element->getId() == id)
|
||||
return element;
|
||||
element->skipData(file);
|
||||
delete element;
|
||||
@ -53,15 +54,15 @@ std::pair<int, T> EBML::readVINT(File &file)
|
||||
{
|
||||
static_assert(sizeof(T) == 8);
|
||||
auto buffer = file.readBlock(1);
|
||||
if (buffer.size() != 1) {
|
||||
if(buffer.size() != 1) {
|
||||
debug("Failed to read VINT size");
|
||||
return {0, 0};
|
||||
}
|
||||
unsigned int nb_bytes = VINTSizeLength<8>(*buffer.begin());
|
||||
if (!nb_bytes)
|
||||
if(!nb_bytes)
|
||||
return {0, 0};
|
||||
|
||||
if (nb_bytes > 1)
|
||||
if(nb_bytes > 1)
|
||||
buffer.append(file.readBlock(nb_bytes - 1));
|
||||
int bits_to_shift = (sizeof(T) * 8) - (7 * nb_bytes);
|
||||
offset_t mask = 0xFFFFFFFFFFFFFFFF >> bits_to_shift;
|
||||
@ -75,11 +76,11 @@ namespace TagLib::EBML {
|
||||
template<typename T>
|
||||
std::pair<int, T> EBML::parseVINT(const ByteVector &buffer)
|
||||
{
|
||||
if (buffer.isEmpty())
|
||||
if(buffer.isEmpty())
|
||||
return {0, 0};
|
||||
|
||||
unsigned int numBytes = VINTSizeLength<8>(*buffer.begin());
|
||||
if (!numBytes)
|
||||
if(!numBytes)
|
||||
return {0, 0};
|
||||
|
||||
int bits_to_shift = (sizeof(T) * 8) - (7 * numBytes);
|
||||
@ -96,7 +97,15 @@ ByteVector EBML::renderVINT(uint64_t number, int minSizeLength)
|
||||
int numBytes = std::max(minSizeLength, minSize(number));
|
||||
number |= (1ULL << (numBytes * 7));
|
||||
static const auto byteOrder = Utils::systemByteOrder();
|
||||
if (byteOrder == Utils::LittleEndian)
|
||||
if(byteOrder == Utils::LittleEndian)
|
||||
number = Utils::byteSwap(static_cast<unsigned long long>(number));
|
||||
return ByteVector((char*) &number + (sizeof(number) - numBytes), numBytes);
|
||||
}
|
||||
|
||||
unsigned long long EBML::randomUID()
|
||||
{
|
||||
static std::random_device device;
|
||||
static std::mt19937 generator(device());
|
||||
static std::uniform_int_distribution<unsigned long long> distribution;
|
||||
return distribution(generator);
|
||||
}
|
||||
|
||||
@ -52,24 +52,23 @@ namespace TagLib {
|
||||
constexpr unsigned int VINTSizeLength(uint8_t firstByte)
|
||||
{
|
||||
static_assert(maxSizeLength >= 1 && maxSizeLength <= 8);
|
||||
if (!firstByte) {
|
||||
if(!firstByte) {
|
||||
debug("VINT with greater than 8 bytes not allowed");
|
||||
return 0;
|
||||
}
|
||||
uint8_t mask = 0b10000000;
|
||||
unsigned int numBytes = 1;
|
||||
while (!(mask & firstByte)) {
|
||||
while(!(mask & firstByte)) {
|
||||
numBytes++;
|
||||
mask >>= 1;
|
||||
}
|
||||
if (numBytes > maxSizeLength) {
|
||||
if(numBytes > maxSizeLength) {
|
||||
debug(Utils::formatString("VINT size length exceeds %i bytes", maxSizeLength));
|
||||
return 0;
|
||||
}
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
//Id readId(File &file);
|
||||
template<typename T>
|
||||
std::pair<int, T> readVINT(File &file);
|
||||
template<typename T>
|
||||
@ -77,18 +76,19 @@ namespace TagLib {
|
||||
Element* findElement(File &file, Element::Id id, offset_t maxLength);
|
||||
Element* findNextElement(File &file, offset_t maxOffset);
|
||||
ByteVector renderVINT(uint64_t number, int minSizeLength);
|
||||
unsigned long long randomUID();
|
||||
|
||||
constexpr int minSize(uint64_t data)
|
||||
{
|
||||
if (data <= 0x7Fu)
|
||||
if(data <= 0x7Fu)
|
||||
return 1;
|
||||
else if (data <= 0x3FFFu)
|
||||
else if(data <= 0x3FFFu)
|
||||
return 2;
|
||||
else if (data <= 0x1FFFFFu)
|
||||
else if(data <= 0x1FFFFFu)
|
||||
return 3;
|
||||
else if (data <= 0xFFFFFFFu)
|
||||
else if(data <= 0xFFFFFFFu)
|
||||
return 4;
|
||||
else if (data <= 0x7FFFFFFFFu)
|
||||
else if(data <= 0x7FFFFFFFFu)
|
||||
return 5;
|
||||
else
|
||||
return 0;
|
||||
@ -96,11 +96,11 @@ namespace TagLib {
|
||||
|
||||
constexpr int idSize(Element::Id id)
|
||||
{
|
||||
if (id <= 0xFF)
|
||||
if(id <= 0xFF)
|
||||
return 1;
|
||||
else if (id <= 0xFFFF)
|
||||
else if(id <= 0xFFFF)
|
||||
return 2;
|
||||
else if (id <= 0xFFFFFF)
|
||||
else if(id <= 0xFFFFFF)
|
||||
return 3;
|
||||
else
|
||||
return 4;
|
||||
|
||||
77
taglib/matroska/matroskaattachedfile.cpp
Normal file
77
taglib/matroska/matroskaattachedfile.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include <memory>
|
||||
#include "matroskaattachedfile.h"
|
||||
#include "tstring.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class Matroska::AttachedFile::AttachedFilePrivate
|
||||
{
|
||||
public:
|
||||
AttachedFilePrivate() {}
|
||||
~AttachedFilePrivate() = default;
|
||||
AttachedFilePrivate(const AttachedFilePrivate &) = delete;
|
||||
AttachedFilePrivate &operator=(const AttachedFilePrivate &) = delete;
|
||||
String fileName;
|
||||
String description;
|
||||
String mediaType;
|
||||
ByteVector data;
|
||||
UID uid = 0;
|
||||
};
|
||||
|
||||
Matroska::AttachedFile::AttachedFile()
|
||||
: d(std::make_unique<AttachedFilePrivate>())
|
||||
{
|
||||
|
||||
}
|
||||
Matroska::AttachedFile::~AttachedFile() = default;
|
||||
|
||||
void Matroska::AttachedFile::setFileName(const String &fileName)
|
||||
{
|
||||
d->fileName = fileName;
|
||||
}
|
||||
|
||||
const String& Matroska::AttachedFile::fileName() const
|
||||
{
|
||||
return d->fileName;
|
||||
}
|
||||
|
||||
void Matroska::AttachedFile::setDescription(const String &description)
|
||||
{
|
||||
d->description = description;
|
||||
}
|
||||
|
||||
const String& Matroska::AttachedFile::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void Matroska::AttachedFile::setMediaType(const String &mediaType)
|
||||
{
|
||||
d->mediaType = mediaType;
|
||||
}
|
||||
|
||||
const String& Matroska::AttachedFile::mediaType() const
|
||||
{
|
||||
return d->mediaType;
|
||||
}
|
||||
|
||||
void Matroska::AttachedFile::setData(const ByteVector &data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
const ByteVector& Matroska::AttachedFile::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void Matroska::AttachedFile::setUID(UID uid)
|
||||
{
|
||||
d->uid = uid;
|
||||
}
|
||||
|
||||
Matroska::AttachedFile::UID Matroska::AttachedFile::uid() const
|
||||
{
|
||||
return d->uid;
|
||||
}
|
||||
57
taglib/matroska/matroskaattachedfile.h
Normal file
57
taglib/matroska/matroskaattachedfile.h
Normal file
@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
* 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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef HAS_MATROSKAATTACHEDFILE_H
|
||||
#define HAS_MATROSKAATTACHEDFILE_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
|
||||
|
||||
namespace TagLib {
|
||||
class String;
|
||||
class ByteVector;
|
||||
namespace Matroska {
|
||||
class TAGLIB_EXPORT AttachedFile
|
||||
{
|
||||
public:
|
||||
using UID = unsigned long long;
|
||||
AttachedFile();
|
||||
~AttachedFile();
|
||||
|
||||
void setFileName(const String &fileName);
|
||||
const String& fileName() const;
|
||||
void setDescription(const String &description);
|
||||
const String& description() const;
|
||||
void setMediaType(const String &mediaType);
|
||||
const String& mediaType() const;
|
||||
void setData(const ByteVector &data);
|
||||
const ByteVector& data() const;
|
||||
void setUID(UID uid);
|
||||
UID uid() const;
|
||||
|
||||
private:
|
||||
class AttachedFilePrivate;
|
||||
std::unique_ptr<AttachedFilePrivate> d;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
97
taglib/matroska/matroskaattachments.cpp
Normal file
97
taglib/matroska/matroskaattachments.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include <memory>
|
||||
#include "matroskaattachments.h"
|
||||
#include "matroskaattachedfile.h"
|
||||
#include "ebmlmkattachments.h"
|
||||
#include "ebmlmasterelement.h"
|
||||
#include "ebmlstringelement.h"
|
||||
#include "ebmlbinaryelement.h"
|
||||
#include "ebmluintelement.h"
|
||||
#include "tlist.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class Matroska::Attachments::AttachmentsPrivate
|
||||
{
|
||||
public:
|
||||
AttachmentsPrivate() {}
|
||||
~AttachmentsPrivate() = default;
|
||||
AttachmentsPrivate(const AttachmentsPrivate &) = delete;
|
||||
AttachmentsPrivate &operator=(const AttachmentsPrivate &) = delete;
|
||||
List<AttachedFile*> files;
|
||||
|
||||
};
|
||||
|
||||
Matroska::Attachments::Attachments()
|
||||
: d(std::make_unique<AttachmentsPrivate>())
|
||||
{
|
||||
d->files.setAutoDelete(true);
|
||||
}
|
||||
Matroska::Attachments::~Attachments() = default;
|
||||
|
||||
void Matroska::Attachments::addAttachedFile(AttachedFile *file)
|
||||
{
|
||||
d->files.append(file);
|
||||
}
|
||||
|
||||
void Matroska::Attachments::removeAttachedFile(AttachedFile *file)
|
||||
{
|
||||
auto it = d->files.find(file);
|
||||
if(it != d->files.end()) {
|
||||
delete *it;
|
||||
d->files.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void Matroska::Attachments::clear()
|
||||
{
|
||||
d->files.clear();
|
||||
}
|
||||
|
||||
const Matroska::Attachments::AttachedFileList& Matroska::Attachments::attachedFileList() const
|
||||
{
|
||||
return d->files;
|
||||
}
|
||||
|
||||
ByteVector Matroska::Attachments::render()
|
||||
{
|
||||
EBML::MkAttachments attachments;
|
||||
for(const auto attachedFile : d->files) {
|
||||
auto attachedFileElement = new EBML::MasterElement(EBML::ElementIDs::MkAttachedFile);
|
||||
|
||||
// Filename
|
||||
auto fileNameElement = new EBML::UTF8StringElement(EBML::ElementIDs::MkAttachedFileName);
|
||||
fileNameElement->setValue(attachedFile->fileName());
|
||||
attachedFileElement->appendElement(fileNameElement);
|
||||
|
||||
// Media/MIME type
|
||||
auto mediaTypeElement = new EBML::Latin1StringElement(EBML::ElementIDs::MkAttachedFileMediaType);
|
||||
mediaTypeElement->setValue(attachedFile->mediaType());
|
||||
attachedFileElement->appendElement(mediaTypeElement);
|
||||
|
||||
// Description
|
||||
const String &description = attachedFile->description();
|
||||
if(!description.isEmpty()) {
|
||||
auto descriptionElement = new EBML::UTF8StringElement(EBML::ElementIDs::MkAttachedFileDescription);
|
||||
descriptionElement->setValue(description);
|
||||
attachedFileElement->appendElement(descriptionElement);
|
||||
}
|
||||
|
||||
// Data
|
||||
auto dataElement = new EBML::BinaryElement(EBML::ElementIDs::MkAttachedFileData);
|
||||
dataElement->setValue(attachedFile->data());
|
||||
attachedFileElement->appendElement(dataElement);
|
||||
|
||||
// UID
|
||||
auto uidElement = new EBML::UIntElement(EBML::ElementIDs::MkAttachedFileUID);
|
||||
AttachedFile::UID uid = attachedFile->uid();
|
||||
if(!uid)
|
||||
uid = EBML::randomUID();
|
||||
uidElement->setValue(uid);
|
||||
attachedFileElement->appendElement(uidElement);
|
||||
|
||||
attachments.appendElement(attachedFileElement);
|
||||
}
|
||||
|
||||
return attachments.render();
|
||||
}
|
||||
60
taglib/matroska/matroskaattachments.h
Normal file
60
taglib/matroska/matroskaattachments.h
Normal file
@ -0,0 +1,60 @@
|
||||
/***************************************************************************
|
||||
* 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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef HAS_MATROSKAATTACHMENTS_H
|
||||
#define HAS_MATROSKAATTACHMENTS_H
|
||||
|
||||
#include <memory>
|
||||
#include "taglib_export.h"
|
||||
#include "tlist.h"
|
||||
#include "matroskaelement.h"
|
||||
|
||||
|
||||
namespace TagLib {
|
||||
namespace EBML {
|
||||
class MkAttachments;
|
||||
}
|
||||
namespace Matroska {
|
||||
class AttachedFile;
|
||||
class File;
|
||||
class TAGLIB_EXPORT Attachments : private Element
|
||||
{
|
||||
public:
|
||||
using AttachedFileList = List<AttachedFile*>;
|
||||
Attachments();
|
||||
virtual ~Attachments();
|
||||
|
||||
void addAttachedFile(AttachedFile *file);
|
||||
void removeAttachedFile(AttachedFile *file);
|
||||
void clear();
|
||||
const AttachedFileList& attachedFileList() const;
|
||||
ByteVector render() override;
|
||||
|
||||
private:
|
||||
friend class EBML::MkAttachments;
|
||||
friend class Matroska::File;
|
||||
class AttachmentsPrivate;
|
||||
std::unique_ptr<AttachmentsPrivate> d;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
44
taglib/matroska/matroskaelement.cpp
Normal file
44
taglib/matroska/matroskaelement.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <memory>
|
||||
#include "matroskaelement.h"
|
||||
#include "tlist.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class Matroska::Element::ElementPrivate
|
||||
{
|
||||
public:
|
||||
ElementPrivate() {}
|
||||
~ElementPrivate() = default;
|
||||
ElementPrivate(const ElementPrivate &) = delete;
|
||||
ElementPrivate &operator=(const ElementPrivate &) = delete;
|
||||
offset_t size = 0;
|
||||
offset_t offset = 0;
|
||||
|
||||
};
|
||||
|
||||
Matroska::Element::Element()
|
||||
: e(std::make_unique<ElementPrivate>())
|
||||
{
|
||||
}
|
||||
Matroska::Element::~Element() = default;
|
||||
|
||||
offset_t Matroska::Element::size() const
|
||||
{
|
||||
return e->size;
|
||||
}
|
||||
|
||||
offset_t Matroska::Element::offset() const
|
||||
{
|
||||
return e->offset;
|
||||
}
|
||||
|
||||
void Matroska::Element::setOffset(offset_t offset)
|
||||
{
|
||||
e->offset = offset;
|
||||
}
|
||||
|
||||
void Matroska::Element::setSize(offset_t size)
|
||||
{
|
||||
e->size = size;
|
||||
}
|
||||
51
taglib/matroska/matroskaelement.h
Normal file
51
taglib/matroska/matroskaelement.h
Normal file
@ -0,0 +1,51 @@
|
||||
/***************************************************************************
|
||||
* 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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef HAS_MATROSKAELEMENT_H
|
||||
#define HAS_MATROSKAELEMENT_H
|
||||
|
||||
#include <memory>
|
||||
#include "taglib_export.h"
|
||||
#include "tutils.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
|
||||
namespace TagLib {
|
||||
namespace Matroska {
|
||||
class TAGLIB_EXPORT Element
|
||||
{
|
||||
public:
|
||||
Element();
|
||||
virtual ~Element();
|
||||
virtual ByteVector render() = 0;
|
||||
offset_t size() const;
|
||||
offset_t offset() const;
|
||||
void setOffset(offset_t offset);
|
||||
void setSize(offset_t size);
|
||||
|
||||
private:
|
||||
class ElementPrivate;
|
||||
std::unique_ptr<ElementPrivate> e;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
#include "matroskafile.h"
|
||||
#include "matroskatag.h"
|
||||
#include "matroskaattachments.h"
|
||||
#include "ebmlutils.h"
|
||||
#include "ebmlelement.h"
|
||||
#include "ebmlmksegment.h"
|
||||
@ -28,6 +29,8 @@
|
||||
#include "tutils.h"
|
||||
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
@ -35,29 +38,27 @@ class Matroska::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete tag;
|
||||
delete attachments;
|
||||
}
|
||||
|
||||
FilePrivate(const FilePrivate &) = delete;
|
||||
FilePrivate &operator=(const FilePrivate &) = delete;
|
||||
Matroska::Tag *tag = nullptr;
|
||||
offset_t tagsOffset = 0;
|
||||
offset_t tagsOriginalSize = 0;
|
||||
Matroska::Attachments *attachments = nullptr;
|
||||
offset_t segmentSizeOffset = 0;
|
||||
offset_t segmentSizeLength = 0;
|
||||
offset_t segmentDataSize = 0;
|
||||
|
||||
//Properties *properties = nullptr;
|
||||
};
|
||||
|
||||
Matroska::File::File(FileName file, bool readProperties)
|
||||
: TagLib::File(file),
|
||||
d(std::make_unique<FilePrivate>())
|
||||
{
|
||||
if (!isOpen()) {
|
||||
if(!isOpen()) {
|
||||
debug("Failed to open matroska file");
|
||||
setValid(false);
|
||||
return;
|
||||
@ -68,7 +69,7 @@ Matroska::File::File(IOStream *stream, bool readProperties)
|
||||
: TagLib::File(stream),
|
||||
d(std::make_unique<FilePrivate>())
|
||||
{
|
||||
if (!isOpen()) {
|
||||
if(!isOpen()) {
|
||||
debug("Failed to open matroska file");
|
||||
setValid(false);
|
||||
return;
|
||||
@ -84,22 +85,33 @@ TagLib::Tag* Matroska::File::tag() const
|
||||
|
||||
Matroska::Tag* Matroska::File::tag(bool create) const
|
||||
{
|
||||
if (d->tag)
|
||||
if(d->tag)
|
||||
return d->tag;
|
||||
else {
|
||||
if (create)
|
||||
if(create)
|
||||
d->tag = new Matroska::Tag();
|
||||
return d->tag;
|
||||
}
|
||||
}
|
||||
|
||||
Matroska::Attachments* Matroska::File::attachments(bool create) const
|
||||
{
|
||||
if(d->attachments)
|
||||
return d->attachments;
|
||||
else {
|
||||
if(create)
|
||||
d->attachments = new Attachments();
|
||||
return d->attachments;
|
||||
}
|
||||
}
|
||||
|
||||
void Matroska::File::read(bool readProperties)
|
||||
{
|
||||
offset_t fileLength = length();
|
||||
|
||||
// Find the EBML Header
|
||||
std::unique_ptr<EBML::Element> head(EBML::Element::factory(*this));
|
||||
if (!head || head->getId() != EBML::ElementIDs::EBMLHeader) {
|
||||
if(!head || head->getId() != EBML::ElementIDs::EBMLHeader) {
|
||||
debug("Failed to find EBML head");
|
||||
setValid(false);
|
||||
return;
|
||||
@ -112,7 +124,7 @@ void Matroska::File::read(bool readProperties)
|
||||
EBML::findElement(*this, EBML::ElementIDs::MkSegment, fileLength - tell())
|
||||
)
|
||||
);
|
||||
if (!segment) {
|
||||
if(!segment) {
|
||||
debug("Failed to find Matroska segment");
|
||||
setValid(false);
|
||||
return;
|
||||
@ -122,32 +134,103 @@ void Matroska::File::read(bool readProperties)
|
||||
d->segmentDataSize = segment->getDataSize();
|
||||
|
||||
// Read the segment into memory from file
|
||||
if (!segment->read(*this)) {
|
||||
if(!segment->read(*this)) {
|
||||
debug("Failed to read segment");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the tag
|
||||
const auto& [tag, tagsOffset, tagsOriginalSize] = segment->parseTag();
|
||||
d->tag = tag;
|
||||
d->tagsOffset = tagsOffset;
|
||||
d->tagsOriginalSize = tagsOriginalSize;
|
||||
d->tag = segment->parseTag();
|
||||
|
||||
// Parse the attachments
|
||||
d->attachments = segment->parseAttachments();
|
||||
|
||||
setValid(true);
|
||||
}
|
||||
|
||||
bool Matroska::File::save()
|
||||
{
|
||||
if (d->tag) {
|
||||
std::vector<Element*> renderListExisting;
|
||||
std::vector<Element*> renderListNew;
|
||||
offset_t newSegmentDataSize = d->segmentDataSize;
|
||||
|
||||
|
||||
if(d->tag) {
|
||||
if(d->tag->size())
|
||||
renderListExisting.push_back(d->tag);
|
||||
else
|
||||
renderListNew.push_back(d->tag);
|
||||
}
|
||||
|
||||
if(d->attachments) {
|
||||
//d->attachments->setOffset(d->tag->offset());
|
||||
//renderListExisting.push_back(d->attachments);
|
||||
if(d->attachments->size())
|
||||
renderListExisting.push_back(d->attachments);
|
||||
else
|
||||
renderListNew.push_back(d->attachments);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Render from end to beginning so we don't have to shift
|
||||
// the file offsets
|
||||
std::sort(renderListExisting.begin(),
|
||||
renderListExisting.end(),
|
||||
[](auto a, auto b) { return a->offset() > b->offset(); }
|
||||
);
|
||||
|
||||
// Overwrite existing elements
|
||||
for(auto element : renderListExisting) {
|
||||
offset_t offset = element->offset();
|
||||
offset_t originalSize = element->size();
|
||||
ByteVector data = element->render();
|
||||
insert(data, offset, originalSize);
|
||||
newSegmentDataSize += (data.size() - originalSize);
|
||||
}
|
||||
|
||||
// Add new elements to the end of file
|
||||
for(auto element : renderListNew) {
|
||||
offset_t offset = length();
|
||||
ByteVector data = element->render();
|
||||
insert(data, offset, 0);
|
||||
newSegmentDataSize += data.size();
|
||||
}
|
||||
|
||||
// Write the new segment data size
|
||||
if(newSegmentDataSize != d->segmentDataSize) {
|
||||
auto segmentDataSizeBuffer = EBML::renderVINT(newSegmentDataSize, d->segmentSizeLength);
|
||||
insert(segmentDataSizeBuffer, d->segmentSizeOffset, d->segmentSizeLength);
|
||||
d->segmentDataSize = newSegmentDataSize;
|
||||
}
|
||||
|
||||
/*
|
||||
auto&& renderElements [&d->segmentDataSize](Element *element) {
|
||||
auto offset = element->offset();
|
||||
if(!offset)
|
||||
}
|
||||
|
||||
if(d->tag) {
|
||||
ByteVector tag = d->tag->render();
|
||||
if (!d->tagsOriginalSize) {
|
||||
d->tagsOffset = d->segmentSizeOffset + d->segmentSizeLength + d->segmentDataSize;
|
||||
auto tagsOriginalSize = d->tag->size();
|
||||
auto tagsOffset = d->tag->offset();
|
||||
|
||||
if(!tagsOriginalSize) {
|
||||
tagsOffset = d->segmentSizeOffset + d->segmentSizeLength + d->segmentDataSize;
|
||||
}
|
||||
insert(tag, d->tagsOffset, d->tagsOriginalSize);
|
||||
d->segmentDataSize += (tag.size() - d->tagsOriginalSize);
|
||||
insert(tag, tagsOffset, tagsOriginalSize);
|
||||
d->segmentDataSize += (tag.size() - tagsOriginalSize);
|
||||
auto segmentDataSizeBuffer = EBML::renderVINT(d->segmentDataSize, d->segmentSizeLength);
|
||||
insert(segmentDataSizeBuffer, d->segmentSizeOffset, d->segmentSizeLength);
|
||||
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if(d->attachments) {
|
||||
ByteVector attachments = d->attachments->render();
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ namespace TagLib {
|
||||
namespace Matroska {
|
||||
class Properties;
|
||||
class Tag;
|
||||
class Attachments;
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
@ -45,6 +46,7 @@ namespace TagLib {
|
||||
File &operator=(const File &) = delete;
|
||||
AudioProperties *audioProperties() const override { return nullptr; }
|
||||
TagLib::Tag *tag() const override;
|
||||
Attachments* attachments(bool create = false) const;
|
||||
Matroska::Tag *tag(bool create) const;
|
||||
bool save() override;
|
||||
//PropertyMap properties() const override { return PropertyMap(); }
|
||||
|
||||
@ -69,8 +69,10 @@ void Matroska::Tag::addSimpleTag(SimpleTag *tag)
|
||||
void Matroska::Tag::removeSimpleTag(SimpleTag *tag)
|
||||
{
|
||||
auto it = d->tags.find(tag);
|
||||
if (it != d->tags.end())
|
||||
if(it != d->tags.end()) {
|
||||
delete *it;
|
||||
d->tags.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void Matroska::Tag::clearSimpleTags()
|
||||
@ -161,7 +163,7 @@ String Matroska::Tag::genre() const
|
||||
unsigned int Matroska::Tag::year() const
|
||||
{
|
||||
auto value = getTag("DATE");
|
||||
if (!value)
|
||||
if(!value)
|
||||
return 0;
|
||||
auto list = value->split("-");
|
||||
return static_cast<unsigned int>(list.front().toInt());
|
||||
@ -170,7 +172,7 @@ unsigned int Matroska::Tag::year() const
|
||||
unsigned int Matroska::Tag::track() const
|
||||
{
|
||||
auto value = getTag("TRACKNUMBER");
|
||||
if (!value)
|
||||
if(!value)
|
||||
return 0;
|
||||
auto list = value->split("-");
|
||||
return static_cast<unsigned int>(list.front().toInt());
|
||||
@ -188,7 +190,7 @@ ByteVector Matroska::Tag::render()
|
||||
targetList.setAutoDelete(true);
|
||||
|
||||
// Build target-based list
|
||||
for (auto tag : d->tags) {
|
||||
for(auto tag : d->tags) {
|
||||
auto targetTypeValue = tag->targetTypeValue();
|
||||
auto it = std::find_if(targetList.begin(),
|
||||
targetList.end(),
|
||||
@ -197,7 +199,7 @@ ByteVector Matroska::Tag::render()
|
||||
return simpleTag->targetTypeValue() == targetTypeValue;
|
||||
}
|
||||
);
|
||||
if (it == targetList.end()) {
|
||||
if(it == targetList.end()) {
|
||||
auto list = new List<SimpleTag*>();
|
||||
list->append(tag);
|
||||
targetList.append(list);
|
||||
@ -205,14 +207,14 @@ ByteVector Matroska::Tag::render()
|
||||
else
|
||||
(*it)->append(tag);
|
||||
}
|
||||
for (auto list : targetList) {
|
||||
for(auto list : targetList) {
|
||||
auto frontTag = list->front();
|
||||
auto targetTypeValue = frontTag->targetTypeValue();
|
||||
auto tag = new EBML::MasterElement(EBML::ElementIDs::MkTag);
|
||||
|
||||
// Build <Tag Targets> element
|
||||
auto targets = new EBML::MasterElement(EBML::ElementIDs::MkTagTargets);
|
||||
if (targetTypeValue != Matroska::SimpleTag::TargetTypeValue::None) {
|
||||
if(targetTypeValue != Matroska::SimpleTag::TargetTypeValue::None) {
|
||||
auto element = new EBML::UIntElement(EBML::ElementIDs::MkTagTargetTypeValue);
|
||||
element->setValue(static_cast<unsigned int>(targetTypeValue));
|
||||
targets->appendElement(element);
|
||||
@ -220,7 +222,7 @@ ByteVector Matroska::Tag::render()
|
||||
tag->appendElement(targets);
|
||||
|
||||
// Build <Simple Tag> element
|
||||
for (auto simpleTag : *list) {
|
||||
for(auto simpleTag : *list) {
|
||||
auto t = new EBML::MasterElement(EBML::ElementIDs::MkSimpleTag);
|
||||
auto tagName = new EBML::UTF8StringElement(EBML::ElementIDs::MkTagName);
|
||||
tagName->setValue(simpleTag->name());
|
||||
@ -299,7 +301,7 @@ bool Matroska::Tag::setTag(const String &key, const String &value)
|
||||
// Workaround Clang issue - no lambda capture of structured bindings
|
||||
const String &name = pair.first;
|
||||
auto targetTypeValue = pair.second;
|
||||
if (name.isEmpty())
|
||||
if(name.isEmpty())
|
||||
return false;
|
||||
removeSimpleTags(
|
||||
[&name, targetTypeValue] (auto t) {
|
||||
@ -307,7 +309,7 @@ bool Matroska::Tag::setTag(const String &key, const String &value)
|
||||
&& t->targetTypeValue() == targetTypeValue;
|
||||
}
|
||||
);
|
||||
if (!value.isEmpty()) {
|
||||
if(!value.isEmpty()) {
|
||||
auto t = new Matroska::SimpleTagString();
|
||||
t->setTargetTypeValue(targetTypeValue);
|
||||
t->setName(name);
|
||||
@ -323,7 +325,7 @@ const String* Matroska::Tag::getTag(const String &key) const
|
||||
// Workaround Clang issue - no lambda capture of structured bindings
|
||||
const String &name = pair.first;
|
||||
auto targetTypeValue = pair.second;
|
||||
if (name.isEmpty())
|
||||
if(name.isEmpty())
|
||||
return nullptr;
|
||||
auto tag = dynamic_cast<const Matroska::SimpleTagString*>(
|
||||
findSimpleTag(
|
||||
@ -342,7 +344,7 @@ std::pair<String, Matroska::SimpleTag::TargetTypeValue> Matroska::Utils::transla
|
||||
simpleTagsTranslation.cend(),
|
||||
[&key](const auto &t) { return key == std::get<0>(t); }
|
||||
);
|
||||
if (it != simpleTagsTranslation.end())
|
||||
if(it != simpleTagsTranslation.end())
|
||||
return { std::get<1>(*it), std::get<2>(*it) };
|
||||
else
|
||||
return { String(), Matroska::SimpleTag::TargetTypeValue::None };
|
||||
@ -363,8 +365,8 @@ String Matroska::Utils::translateTag(const String &name, Matroska::SimpleTag::Ta
|
||||
PropertyMap Matroska::Tag::setProperties(const PropertyMap &propertyMap)
|
||||
{
|
||||
PropertyMap unsupportedProperties;
|
||||
for (const auto& [key, value] : propertyMap) {
|
||||
if (!setTag(key, value.toString()))
|
||||
for(const auto& [key, value] : propertyMap) {
|
||||
if(!setTag(key, value.toString()))
|
||||
unsupportedProperties[key] = value;
|
||||
}
|
||||
return unsupportedProperties;
|
||||
@ -374,10 +376,10 @@ PropertyMap Matroska::Tag::properties() const
|
||||
{
|
||||
PropertyMap properties;
|
||||
Matroska::SimpleTagString *tStr = nullptr;
|
||||
for (auto simpleTag : d->tags) {
|
||||
if ((tStr = dynamic_cast<Matroska::SimpleTagString*>(simpleTag))) {
|
||||
for(auto simpleTag : d->tags) {
|
||||
if((tStr = dynamic_cast<Matroska::SimpleTagString*>(simpleTag))) {
|
||||
String key = Matroska::Utils::translateTag(tStr->name(), tStr->targetTypeValue());
|
||||
if (!key.isEmpty() && !properties.contains(key))
|
||||
if(!key.isEmpty() && !properties.contains(key))
|
||||
properties[key] = tStr->value();
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,12 +29,17 @@
|
||||
#include "tstring.h"
|
||||
#include "tlist.h"
|
||||
#include "matroskafile.h"
|
||||
#include "matroskaelement.h"
|
||||
#include "matroskasimpletag.h"
|
||||
|
||||
namespace TagLib {
|
||||
namespace EBML {
|
||||
class MkTags;
|
||||
}
|
||||
|
||||
namespace Matroska {
|
||||
using SimpleTagsList = List<SimpleTag*>;
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag, private Element
|
||||
{
|
||||
public:
|
||||
Tag();
|
||||
@ -58,6 +63,7 @@ namespace TagLib {
|
||||
void setYear(unsigned int i) override;
|
||||
void setTrack(unsigned int i) override;
|
||||
bool isEmpty() const override;
|
||||
ByteVector render() override;
|
||||
PropertyMap properties() const override;
|
||||
PropertyMap setProperties(const PropertyMap &propertyMap) override;
|
||||
template <typename T>
|
||||
@ -65,9 +71,9 @@ namespace TagLib {
|
||||
{
|
||||
auto &list = simpleTagsListPrivate();
|
||||
int numRemoved = 0;
|
||||
for (auto it = list.begin(); it != list.end();) {
|
||||
for(auto it = list.begin(); it != list.end();) {
|
||||
it = std::find_if(it, list.end(), std::forward<T>(p));
|
||||
if (it != list.end()) {
|
||||
if(it != list.end()) {
|
||||
delete *it;
|
||||
*it = nullptr;
|
||||
it = list.erase(it);
|
||||
@ -81,15 +87,16 @@ namespace TagLib {
|
||||
SimpleTagsList findSimpleTags(T&& p)
|
||||
{
|
||||
auto &list = simpleTagsListPrivate();
|
||||
for (auto it = list.begin(); it != list.end();) {
|
||||
for(auto it = list.begin(); it != list.end();) {
|
||||
it = std::find_if(it, list.end(), std::forward<T>(p));
|
||||
if (it != list.end()) {
|
||||
if(it != list.end()) {
|
||||
list.append(*it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const Matroska::SimpleTag* findSimpleTag(T&& p) const
|
||||
{
|
||||
@ -97,6 +104,7 @@ namespace TagLib {
|
||||
auto it = std::find_if(list.begin(), list.end(), std::forward<T>(p));
|
||||
return it != list.end() ? *it : nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Matroska::SimpleTag* findSimpleTag(T&&p)
|
||||
{
|
||||
@ -107,7 +115,7 @@ namespace TagLib {
|
||||
|
||||
private:
|
||||
friend class Matroska::File;
|
||||
ByteVector render();
|
||||
friend class EBML::MkTags;
|
||||
SimpleTagsList& simpleTagsListPrivate();
|
||||
const SimpleTagsList& simpleTagsListPrivate() const;
|
||||
bool setTag(const String &key, const String &value);
|
||||
|
||||
Reference in New Issue
Block a user