Replace raw pointers by smart pointers

Also improve type safety and consistency.
This commit is contained in:
Urs Fleisch
2025-08-19 16:33:40 +02:00
parent cfade6d082
commit 8d02484804
35 changed files with 552 additions and 422 deletions

View File

@ -34,6 +34,10 @@ namespace TagLib {
Element(id, sizeLength, dataSize)
{
}
BinaryElement(Id id, int sizeLength, offset_t dataSize, offset_t) :
Element(id, sizeLength, dataSize)
{
}
explicit BinaryElement(Id id) :
Element(id, 0, 0)

View File

@ -39,12 +39,15 @@
using namespace TagLib;
EBML::Element *EBML::Element::factory(File &file)
#define RETURN_ELEMENT_FOR_CASE(eid) \
case (eid): return make_unique_element<eid>(id, sizeLength, dataSize, offset)
std::unique_ptr<EBML::Element> EBML::Element::factory(File &file)
{
// Get the element ID
offset_t offset = file.tell();
Id id = readId(file);
if(!id) {
unsigned int uintId = readId(file);
if(!uintId) {
debug("Failed to parse EMBL ElementID");
return nullptr;
}
@ -55,73 +58,62 @@ EBML::Element *EBML::Element::factory(File &file)
return nullptr;
// Return the subclass
// The enum switch without default will give us a warning if an ID is missing
auto id = static_cast<Id>(uintId);
switch(id) {
case ElementIDs::EBMLHeader:
return new Element(id, sizeLength, dataSize);
case ElementIDs::MkSegment:
return new MkSegment(sizeLength, dataSize, offset);
case ElementIDs::MkInfo:
return new MkInfo(sizeLength, dataSize, offset);
case ElementIDs::MkTracks:
return new MkTracks(sizeLength, dataSize, offset);
case ElementIDs::MkTags:
return new MkTags(sizeLength, dataSize, offset);
case ElementIDs::MkAttachments:
return new MkAttachments(sizeLength, dataSize, offset);
case ElementIDs::MkTag:
case ElementIDs::MkTagTargets:
case ElementIDs::MkSimpleTag:
case ElementIDs::MkAttachedFile:
case ElementIDs::MkSeek:
case ElementIDs::MkTrackEntry:
case ElementIDs::MkAudio:
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:
case ElementIDs::MkCodecID:
return new Latin1StringElement(id, sizeLength, dataSize);
case ElementIDs::MkTagTargetTypeValue:
case ElementIDs::MkAttachedFileUID:
case ElementIDs::MkSeekPosition:
case ElementIDs::MkTimestampScale:
case ElementIDs::MkBitDepth:
case ElementIDs::MkChannels:
return new UIntElement(id, sizeLength, dataSize);
case ElementIDs::MkAttachedFileData:
case ElementIDs::MkSeekID:
return new BinaryElement(id, sizeLength, dataSize);
case ElementIDs::MkDuration:
case ElementIDs::MkSamplingFrequency:
return new FloatElement(id, sizeLength, dataSize);
case ElementIDs::MkSeekHead:
return new MkSeekHead(sizeLength, dataSize, offset);
case ElementIDs::VoidElement:
return new VoidElement(sizeLength, dataSize);
default:
return new Element(id, sizeLength, dataSize);
RETURN_ELEMENT_FOR_CASE(Id::EBMLHeader);
RETURN_ELEMENT_FOR_CASE(Id::MkSegment);
RETURN_ELEMENT_FOR_CASE(Id::MkInfo);
RETURN_ELEMENT_FOR_CASE(Id::MkTracks);
RETURN_ELEMENT_FOR_CASE(Id::MkTags);
RETURN_ELEMENT_FOR_CASE(Id::MkAttachments);
RETURN_ELEMENT_FOR_CASE(Id::MkTag);
RETURN_ELEMENT_FOR_CASE(Id::MkTagTargets);
RETURN_ELEMENT_FOR_CASE(Id::MkSimpleTag);
RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFile);
RETURN_ELEMENT_FOR_CASE(Id::MkSeek);
RETURN_ELEMENT_FOR_CASE(Id::MkTrackEntry);
RETURN_ELEMENT_FOR_CASE(Id::MkAudio);
RETURN_ELEMENT_FOR_CASE(Id::MkTagName);
RETURN_ELEMENT_FOR_CASE(Id::MkTagString);
RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFileName);
RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFileDescription);
RETURN_ELEMENT_FOR_CASE(Id::MkTagLanguage);
RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFileMediaType);
RETURN_ELEMENT_FOR_CASE(Id::MkCodecID);
RETURN_ELEMENT_FOR_CASE(Id::MkTagTargetTypeValue);
RETURN_ELEMENT_FOR_CASE(Id::MkTagsLanguageDefault);
RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFileUID);
RETURN_ELEMENT_FOR_CASE(Id::MkSeekPosition);
RETURN_ELEMENT_FOR_CASE(Id::MkTimestampScale);
RETURN_ELEMENT_FOR_CASE(Id::MkBitDepth);
RETURN_ELEMENT_FOR_CASE(Id::MkChannels);
RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFileData);
RETURN_ELEMENT_FOR_CASE(Id::MkSeekID);
RETURN_ELEMENT_FOR_CASE(Id::MkDuration);
RETURN_ELEMENT_FOR_CASE(Id::MkSamplingFrequency);
RETURN_ELEMENT_FOR_CASE(Id::MkSeekHead);
RETURN_ELEMENT_FOR_CASE(Id::VoidElement);
RETURN_ELEMENT_FOR_CASE(Id::MkCluster);
RETURN_ELEMENT_FOR_CASE(Id::MkCodecState);
RETURN_ELEMENT_FOR_CASE(Id::MkTagBinary);
RETURN_ELEMENT_FOR_CASE(Id::MkCues);
RETURN_ELEMENT_FOR_CASE(Id::MkCuePoint);
RETURN_ELEMENT_FOR_CASE(Id::MkCueTime);
RETURN_ELEMENT_FOR_CASE(Id::MkCueTrackPositions);
RETURN_ELEMENT_FOR_CASE(Id::MkCueTrack);
RETURN_ELEMENT_FOR_CASE(Id::MkCueClusterPosition);
RETURN_ELEMENT_FOR_CASE(Id::MkCueRelativePosition);
RETURN_ELEMENT_FOR_CASE(Id::MkCueDuration);
RETURN_ELEMENT_FOR_CASE(Id::MkCueBlockNumber);
RETURN_ELEMENT_FOR_CASE(Id::MkCueCodecState);
RETURN_ELEMENT_FOR_CASE(Id::MkCueReference);
RETURN_ELEMENT_FOR_CASE(Id::MkCueRefTime);
}
return std::make_unique<Element>(id, sizeLength, dataSize);
}
EBML::Element::Id EBML::Element::readId(File &file)
unsigned int EBML::Element::readId(File &file)
{
auto buffer = file.readBlock(1);
if(buffer.size() != 1) {
@ -161,6 +153,7 @@ ByteVector EBML::Element::renderId() const
{
int numBytes = idSize(id);
static const auto byteOrder = Utils::systemByteOrder();
uint32_t data = byteOrder == Utils::LittleEndian ? Utils::byteSwap(id) : id;
auto uintId = static_cast<uint32_t>(id);
uint32_t data = byteOrder == Utils::LittleEndian ? Utils::byteSwap(uintId) : uintId;
return ByteVector(reinterpret_cast<char *>(&data) + (4 - numBytes), numBytes);
}

View File

@ -22,6 +22,7 @@
#define TAGLIB_EBMLELEMENT_H
#ifndef DO_NOT_DOCUMENT
#include <memory>
#include "tfile.h"
#include "tutils.h"
#include "taglib.h"
@ -30,11 +31,67 @@ namespace TagLib::EBML {
class Element
{
public:
using Id = unsigned int;
enum class Id : unsigned int
{
EBMLHeader = 0x1A45DFA3,
VoidElement = 0xEC,
MkSegment = 0x18538067,
MkTags = 0x1254C367,
MkTag = 0x7373,
MkTagTargets = 0x63C0,
MkTagTargetTypeValue = 0x68CA,
MkSimpleTag = 0x67C8,
MkTagName = 0x45A3,
MkTagLanguage = 0x447A,
MkTagBinary = 0x4485,
MkTagString = 0x4487,
MkTagsTagLanguage = 0x447A,
MkTagsLanguageDefault = 0x4484,
MkAttachments = 0x1941A469,
MkAttachedFile = 0x61A7,
MkAttachedFileDescription = 0x467E,
MkAttachedFileName = 0x466E,
MkAttachedFileMediaType = 0x4660,
MkAttachedFileData = 0x465C,
MkAttachedFileUID = 0x46AE,
MkSeekHead = 0x114D9B74,
MkSeek = 0x4DBB,
MkSeekID = 0x53AB,
MkSeekPosition = 0x53AC,
MkCluster = 0x1F43B675,
MkCodecState = 0xA4,
MkCues = 0x1C53BB6B,
MkCuePoint = 0xBB,
MkCueTime = 0xB3,
MkCueTrackPositions = 0xB7,
MkCueTrack = 0xF7,
MkCueClusterPosition = 0xF1,
MkCueRelativePosition = 0xF0,
MkCueDuration = 0xB2,
MkCueBlockNumber = 0x5378,
MkCueCodecState = 0xEA,
MkCueReference = 0xDB,
MkCueRefTime = 0x96,
MkInfo = 0x1549A966,
MkTimestampScale = 0x2AD7B1,
MkDuration = 0x4489,
MkTracks = 0x1654AE6B,
MkTrackEntry = 0xAE,
MkCodecID = 0x86,
MkAudio = 0xE1,
MkSamplingFrequency = 0xB5,
MkBitDepth = 0x6264,
MkChannels = 0x9F,
};
Element(Id id, int sizeLength, offset_t dataSize) :
id(id), sizeLength(sizeLength), dataSize(dataSize)
{
}
Element(Id id, int sizeLength, offset_t dataSize, offset_t) :
id(id), sizeLength(sizeLength), dataSize(dataSize)
{
}
virtual ~Element() = default;
virtual bool read(File &file)
{
@ -49,8 +106,8 @@ namespace TagLib::EBML {
int64_t getDataSize() const { return dataSize; }
ByteVector renderId() const;
virtual ByteVector render();
static Element *factory(File &file);
static Id readId(File &file);
static std::unique_ptr<Element> factory(File &file);
static unsigned int readId(File &file);
protected:
Id id;
@ -58,57 +115,104 @@ namespace TagLib::EBML {
offset_t dataSize;
};
namespace ElementIDs {
inline constexpr Element::Id EBMLHeader = 0x1A45DFA3;
inline constexpr Element::Id VoidElement = 0xEC;
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 MkTagBinary = 0x4485;
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;
inline constexpr Element::Id MkSeekHead = 0x114D9B74;
inline constexpr Element::Id MkSeek = 0x4DBB;
inline constexpr Element::Id MkSeekID = 0x53AB;
inline constexpr Element::Id MkSeekPosition = 0x53AC;
inline constexpr Element::Id MkCluster = 0x1F43B675;
inline constexpr Element::Id MkCodecState = 0xA4;
inline constexpr Element::Id MkCues = 0x1C53BB6B;
inline constexpr Element::Id MkCuePoint = 0xBB;
inline constexpr Element::Id MkCueTime = 0xB3;
inline constexpr Element::Id MkCueTrackPositions = 0xB7;
inline constexpr Element::Id MkCueTrack = 0xF7;
inline constexpr Element::Id MkCueClusterPosition = 0xF1;
inline constexpr Element::Id MkCueRelativePosition = 0xF0;
inline constexpr Element::Id MkCueDuration = 0xB2;
inline constexpr Element::Id MkCueBlockNumber = 0x5378;
inline constexpr Element::Id MkCueCodecState = 0xEA;
inline constexpr Element::Id MkCueReference = 0xDB;
inline constexpr Element::Id MkCueRefTime = 0x96;
inline constexpr Element::Id MkInfo = 0x1549A966;
inline constexpr Element::Id MkTimestampScale = 0x2AD7B1;
inline constexpr Element::Id MkDuration = 0x4489;
inline constexpr Element::Id MkTracks = 0x1654AE6B;
inline constexpr Element::Id MkTrackEntry = 0xAE;
inline constexpr Element::Id MkCodecID = 0x86;
inline constexpr Element::Id MkAudio = 0xE1;
inline constexpr Element::Id MkSamplingFrequency = 0xB5;
inline constexpr Element::Id MkBitDepth = 0x6264;
inline constexpr Element::Id MkChannels = 0x9F;
// Template specializations to ensure that elements for the different IDs
// are consistently created and cast. They provide a mapping between IDs
// and Element subclasses. The switch in factory() makes sure that the
// template for all IDs are instantiated, i.e. that every ID has its Element
// subclass mapped.
class MasterElement;
class UIntElement;
class BinaryElement;
class FloatElement;
class MkSegment;
class MkInfo;
class MkTracks;
class MkTags;
class MkAttachments;
class MkSeekHead;
class VoidElement;
template <String::Type t>
class StringElement;
using UTF8StringElement = StringElement<String::UTF8>;
using Latin1StringElement = StringElement<String::Latin1>;
template <Element::Id ID>
struct GetElementTypeById;
template <> struct GetElementTypeById<Element::Id::EBMLHeader> { using type = Element; };
template <> struct GetElementTypeById<Element::Id::MkSegment> { using type = MkSegment; };
template <> struct GetElementTypeById<Element::Id::MkInfo> { using type = MkInfo; };
template <> struct GetElementTypeById<Element::Id::MkTracks> { using type = MkTracks; };
template <> struct GetElementTypeById<Element::Id::MkTags> { using type = MkTags; };
template <> struct GetElementTypeById<Element::Id::MkAttachments> { using type = MkAttachments; };
template <> struct GetElementTypeById<Element::Id::MkTag> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkTagTargets> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkSimpleTag> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkAttachedFile> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkSeek> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkTrackEntry> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkAudio> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkCuePoint> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkCueTrackPositions> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkCueReference> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkCluster> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkCues> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::MkTagName> { using type = UTF8StringElement; };
template <> struct GetElementTypeById<Element::Id::MkTagString> { using type = UTF8StringElement; };
template <> struct GetElementTypeById<Element::Id::MkAttachedFileName> { using type = UTF8StringElement; };
template <> struct GetElementTypeById<Element::Id::MkAttachedFileDescription> { using type = UTF8StringElement; };
template <> struct GetElementTypeById<Element::Id::MkTagLanguage> { using type = Latin1StringElement; };
template <> struct GetElementTypeById<Element::Id::MkAttachedFileMediaType> { using type = Latin1StringElement; };
template <> struct GetElementTypeById<Element::Id::MkCodecID> { using type = Latin1StringElement; };
template <> struct GetElementTypeById<Element::Id::MkTagTargetTypeValue> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkAttachedFileUID> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkSeekPosition> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkTimestampScale> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkBitDepth> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkChannels> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkCueTime> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkCueTrack> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkCueClusterPosition> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkCueRelativePosition> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkCueDuration> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkCueBlockNumber> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkCueCodecState> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkCueRefTime> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkTagsLanguageDefault> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkAttachedFileData> { using type = BinaryElement; };
template <> struct GetElementTypeById<Element::Id::MkSeekID> { using type = BinaryElement; };
template <> struct GetElementTypeById<Element::Id::MkTagBinary> { using type = BinaryElement; };
template <> struct GetElementTypeById<Element::Id::MkCodecState> { using type = BinaryElement; };
template <> struct GetElementTypeById<Element::Id::MkDuration> { using type = FloatElement; };
template <> struct GetElementTypeById<Element::Id::MkSamplingFrequency> { using type = FloatElement; };
template <> struct GetElementTypeById<Element::Id::MkSeekHead> { using type = MkSeekHead; };
template <> struct GetElementTypeById<Element::Id::VoidElement> { using type = VoidElement; };
template <Element::Id ID, typename T=typename GetElementTypeById<ID>::type>
const T *element_cast(const std::unique_ptr<Element> &ptr)
{
return static_cast<const T *>(ptr.get());
}
template <Element::Id ID, typename T=typename GetElementTypeById<ID>::type>
std::unique_ptr<T> element_cast(std::unique_ptr<Element> &&ptr)
{
return std::unique_ptr<T>(static_cast<T *>(ptr.release()));
}
template <Element::Id ID, typename T=typename GetElementTypeById<ID>::type>
std::unique_ptr<T> make_unique_element(Element::Id id, int sizeLength, offset_t dataSize, offset_t offset)
{
return std::make_unique<T>(id, sizeLength, dataSize, offset);
}
template <Element::Id ID, typename T=typename GetElementTypeById<ID>::type>
std::unique_ptr<T> make_unique_element()
{
return std::make_unique<T>(ID, 0, 0, 0);
}
}
#endif

View File

@ -43,6 +43,10 @@ namespace TagLib {
Element(id, sizeLength, dataSize)
{
}
FloatElement(Id id, int sizeLength, offset_t dataSize, offset_t) :
Element(id, sizeLength, dataSize)
{
}
explicit FloatElement(Id id) :
FloatElement(id, 0, 0)

View File

@ -25,20 +25,21 @@
using namespace TagLib;
EBML::MasterElement::~MasterElement()
EBML::MasterElement::~MasterElement() = default;
void EBML::MasterElement::appendElement(std::unique_ptr<Element>&& element)
{
for(auto element : elements)
delete element;
elements.push_back(std::move(element));
}
bool EBML::MasterElement::read(File &file)
{
offset_t maxOffset = file.tell() + dataSize;
Element *element = nullptr;
std::unique_ptr<Element> element;
while((element = findNextElement(file, maxOffset))) {
if(!element->read(file))
return false;
elements.append(element);
elements.push_back(std::move(element));
}
return file.tell() == maxOffset;
}
@ -47,7 +48,7 @@ ByteVector EBML::MasterElement::render()
{
ByteVector buffer = renderId();
ByteVector data;
for(auto element : elements)
for(const auto &element : elements)
data.append(element->render());
dataSize = data.size();
buffer.append(renderVINT(dataSize, 0));

View File

@ -44,11 +44,13 @@ namespace TagLib::EBML {
offset_t getOffset() const { return offset; }
bool read(File &file) override;
ByteVector render() override;
void appendElement(Element *element) { elements.append(element); }
List<Element *>::Iterator begin() { return elements.begin(); }
List<Element *>::Iterator end() { return elements.end(); }
List<Element *>::ConstIterator cbegin() const { return elements.cbegin(); }
List<Element *>::ConstIterator cend() const { return elements.cend(); }
void appendElement(std::unique_ptr<Element> &&element);
std::list<std::unique_ptr<Element>>::iterator begin() { return elements.begin(); }
std::list<std::unique_ptr<Element>>::iterator end() { return elements.end(); }
std::list<std::unique_ptr<Element>>::const_iterator begin() const { return elements.begin(); }
std::list<std::unique_ptr<Element>>::const_iterator end() const { return elements.end(); }
std::list<std::unique_ptr<Element>>::const_iterator cbegin() const { return elements.cbegin(); }
std::list<std::unique_ptr<Element>>::const_iterator cend() const { return elements.cend(); }
offset_t getPadding() const { return padding; }
void setPadding(offset_t padding) { this->padding = padding; }
offset_t getMinRenderSize() const { return minRenderSize; }
@ -58,7 +60,7 @@ namespace TagLib::EBML {
offset_t offset;
offset_t padding = 0;
offset_t minRenderSize = 0;
List<Element *> elements;
std::list<std::unique_ptr<Element>> elements;
};
}

View File

@ -27,14 +27,14 @@
using namespace TagLib;
Matroska::Attachments *EBML::MkAttachments::parse()
std::unique_ptr<Matroska::Attachments> EBML::MkAttachments::parse()
{
auto attachments = new Matroska::Attachments();
auto attachments = std::make_unique<Matroska::Attachments>();
attachments->setOffset(offset);
attachments->setSize(getSize());
for(auto element : elements) {
if(element->getId() != ElementIDs::MkAttachedFile)
for(const auto &element : elements) {
if(element->getId() != Id::MkAttachedFile)
continue;
const String *filename = nullptr;
@ -42,19 +42,19 @@ Matroska::Attachments *EBML::MkAttachments::parse()
const String *mediaType = nullptr;
const ByteVector *data = nullptr;
Matroska::AttachedFile::UID uid = 0;
auto attachedFile = static_cast<MasterElement *>(element);
for(auto attachedFileChild : *attachedFile) {
auto attachedFile = element_cast<Id::MkAttachedFile>(element);
for(const 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(id == Id::MkAttachedFileName)
filename = &(element_cast<Id::MkAttachedFileName>(attachedFileChild)->getValue());
else if(id == Id::MkAttachedFileData)
data = &(element_cast<Id::MkAttachedFileData>(attachedFileChild)->getValue());
else if(id == Id::MkAttachedFileDescription)
description = &(element_cast<Id::MkAttachedFileDescription>(attachedFileChild)->getValue());
else if(id == Id::MkAttachedFileMediaType)
mediaType = &(element_cast<Id::MkAttachedFileMediaType>(attachedFileChild)->getValue());
else if(id == Id::MkAttachedFileUID)
uid = element_cast<Id::MkAttachedFileUID>(attachedFileChild)->getValue();
}
if(!(filename && data))
continue;

View File

@ -35,14 +35,18 @@ namespace TagLib {
{
public:
MkAttachments(int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(ElementIDs::MkAttachments, sizeLength, dataSize, offset)
MasterElement(Id::MkAttachments, sizeLength, dataSize, offset)
{
}
MkAttachments(Id, int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(Id::MkAttachments, sizeLength, dataSize, offset)
{
}
MkAttachments() :
MasterElement(ElementIDs::MkAttachments, 0, 0, 0)
MasterElement(Id::MkAttachments, 0, 0, 0)
{
}
Matroska::Attachments *parse();
std::unique_ptr<Matroska::Attachments> parse();
};
}
}

View File

@ -29,48 +29,48 @@ Matroska::Cues *EBML::MkCues::parse()
auto cues = new Matroska::Cues();
cues->setOffset(offset);
cues->setSize(getSize());
cues->setID(id);
cues->setID(static_cast<Matroska::Element::ID>(id));
for(auto cuesChild : elements) {
if(cuesChild->getId() != ElementIDs::MkCuePoint)
for(const auto &cuesChild : elements) {
if(cuesChild->getId() != Id::MkCuePoint)
continue;
auto cuePointElement = static_cast<MasterElement *>(cuesChild);
auto cuePoint = new Matroska::CuePoint();
auto cuePointElement = element_cast<Id::MkCuePoint>(cuesChild);
auto cuePoint = std::make_unique<Matroska::CuePoint>();
for(auto cuePointChild : *cuePointElement) {
for(const auto &cuePointChild : *cuePointElement) {
Id id = cuePointChild->getId();
if(id == ElementIDs::MkCueTime)
cuePoint->setTime(static_cast<UIntElement *>(cuePointChild)->getValue());
else if(id == ElementIDs::MkCueTrackPositions) {
auto cueTrack = new Matroska::CueTrack();
auto cueTrackElement = static_cast<MasterElement *>(cuePointChild);
for(auto cueTrackChild : *cueTrackElement) {
if(id == Id::MkCueTime)
cuePoint->setTime(element_cast<Id::MkCueTime>(cuePointChild)->getValue());
else if(id == Id::MkCueTrackPositions) {
auto cueTrack = std::make_unique<Matroska::CueTrack>();
auto cueTrackElement = element_cast<Id::MkCueTrackPositions>(cuePointChild);
for(const auto &cueTrackChild : *cueTrackElement) {
Id trackId = cueTrackChild->getId();
if(trackId == ElementIDs::MkCueTrack)
cueTrack->setTrackNumber(static_cast<UIntElement *>(cueTrackChild)->getValue());
else if(trackId == ElementIDs::MkCueClusterPosition)
cueTrack->setClusterPosition(static_cast<UIntElement *>(cueTrackChild)->getValue());
else if(trackId == ElementIDs::MkCueRelativePosition)
cueTrack->setRelativePosition(static_cast<UIntElement *>(cueTrackChild)->getValue());
else if(trackId == ElementIDs::MkCueDuration)
cueTrack->setDuration(static_cast<UIntElement *>(cueTrackChild)->getValue());
else if(trackId == ElementIDs::MkCueBlockNumber)
cueTrack->setBlockNumber(static_cast<UIntElement *>(cueTrackChild)->getValue());
else if(trackId == ElementIDs::MkCueCodecState)
cueTrack->setCodecState(static_cast<UIntElement *>(cueTrackChild)->getValue());
else if(trackId == ElementIDs::MkCueReference) {
auto cueReference = static_cast<MasterElement *>(cueTrackChild);
for(auto cueReferenceChild : *cueReference) {
if(cueReferenceChild->getId() != ElementIDs::MkCueReference)
if(trackId == Id::MkCueTrack)
cueTrack->setTrackNumber(element_cast<Id::MkCueTrack>(cueTrackChild)->getValue());
else if(trackId == Id::MkCueClusterPosition)
cueTrack->setClusterPosition(element_cast<Id::MkCueClusterPosition>(cueTrackChild)->getValue());
else if(trackId == Id::MkCueRelativePosition)
cueTrack->setRelativePosition(element_cast<Id::MkCueRelativePosition>(cueTrackChild)->getValue());
else if(trackId == Id::MkCueDuration)
cueTrack->setDuration(element_cast<Id::MkCueDuration>(cueTrackChild)->getValue());
else if(trackId == Id::MkCueBlockNumber)
cueTrack->setBlockNumber(element_cast<Id::MkCueBlockNumber>(cueTrackChild)->getValue());
else if(trackId == Id::MkCueCodecState)
cueTrack->setCodecState(element_cast<Id::MkCueCodecState>(cueTrackChild)->getValue());
else if(trackId == Id::MkCueReference) {
auto cueReference = element_cast<Id::MkCueReference>(cueTrackChild);
for(const auto &cueReferenceChild : *cueReference) {
if(cueReferenceChild->getId() != Id::MkCueRefTime)
continue;
cueTrack->addReferenceTime(static_cast<UIntElement *>(cueReferenceChild)->getValue());
cueTrack->addReferenceTime(element_cast<Id::MkCueRefTime>(cueReferenceChild)->getValue());
}
}
}
cuePoint->addCueTrack(cueTrack);
cuePoint->addCueTrack(std::move(cueTrack));
}
}
cues->addCuePoint(cuePoint);
cues->addCuePoint(std::move(cuePoint));
}
return cues;
}

View File

@ -36,11 +36,11 @@ namespace TagLib {
{
public:
MkCues(int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(ElementIDs::MkCues, sizeLength, dataSize, offset)
MasterElement(Id::MkCues, sizeLength, dataSize, offset)
{
}
MkCues() :
MasterElement(ElementIDs::MkCues, 0, 0, 0)
MasterElement(Id::MkCues, 0, 0, 0)
{
}

View File

@ -38,13 +38,13 @@ void EBML::MkInfo::parse(Matroska::Properties *properties)
unsigned long long timestampScale = 1000000;
double duration = 0.0;
for(auto element : elements) {
for(const auto &element : elements) {
Id id = element->getId();
if (id == ElementIDs::MkTimestampScale) {
timestampScale = static_cast<UIntElement *>(element)->getValue();
if (id == Id::MkTimestampScale) {
timestampScale = element_cast<Id::MkTimestampScale>(element)->getValue();
}
else if (id == ElementIDs::MkDuration) {
duration = static_cast<FloatElement *>(element)->getValueAsDouble();
else if (id == Id::MkDuration) {
duration = element_cast<Id::MkDuration>(element)->getValueAsDouble();
}
}

View File

@ -40,11 +40,15 @@ namespace TagLib {
{
public:
MkInfo(int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(ElementIDs::MkInfo, sizeLength, dataSize, offset)
MasterElement(Id::MkInfo, sizeLength, dataSize, offset)
{
}
MkInfo(Id, int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(Id::MkInfo, sizeLength, dataSize, offset)
{
}
MkInfo() :
MasterElement(ElementIDs::MkInfo, 0, 0, 0)
MasterElement(Id::MkInfo, 0, 0, 0)
{
}
void parse(Matroska::Properties * properties);

View File

@ -31,21 +31,21 @@ std::unique_ptr<Matroska::SeekHead> EBML::MkSeekHead::parse()
seekHead->setOffset(offset);
seekHead->setSize(getSize() + padding);
for(auto element : elements) {
if(element->getId() != ElementIDs::MkSeek)
for(const auto &element : elements) {
if(element->getId() != Id::MkSeek)
continue;
auto seekElement = static_cast<MasterElement *>(element);
auto seekElement = element_cast<Id::MkSeek>(element);
Matroska::Element::ID entryId = 0;
offset_t offset = 0;
for(auto seekElementChild : *seekElement) {
for(const auto &seekElementChild : *seekElement) {
Id id = seekElementChild->getId();
if(id == ElementIDs::MkSeekID && !entryId) {
auto data = static_cast<BinaryElement *>(seekElementChild)->getValue();
if(id == Id::MkSeekID && !entryId) {
auto data = element_cast<Id::MkSeekID>(seekElementChild)->getValue();
if(data.size() == 4)
entryId = data.toUInt(true);
}
else if(id == ElementIDs::MkSeekPosition && !offset)
offset = static_cast<UIntElement *>(seekElementChild)->getValue();
else if(id == Id::MkSeekPosition && !offset)
offset = element_cast<Id::MkSeekPosition>(seekElementChild)->getValue();
}
if(entryId && offset)
seekHead->addEntry(entryId, offset);

View File

@ -34,15 +34,19 @@ namespace TagLib {
{
public:
MkSeekHead(int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(ElementIDs::MkSeekHead, sizeLength, dataSize, offset)
MasterElement(Id::MkSeekHead, sizeLength, dataSize, offset)
{
}
MkSeekHead(Id, int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(Id::MkSeekHead, sizeLength, dataSize, offset)
{
}
MkSeekHead() :
MasterElement(ElementIDs::MkSeekHead, 0, 0, 0)
MasterElement(Id::MkSeekHead, 0, 0, 0)
{
}
Matroska::SeekHead *parse();
std::unique_ptr<Matroska::SeekHead> parse();
};
}
}

View File

@ -33,81 +33,73 @@
using namespace TagLib;
EBML::MkSegment::~MkSegment()
{
delete tags;
delete attachments;
delete seekHead;
delete info;
delete tracks;
}
EBML::MkSegment::~MkSegment() = default;
bool EBML::MkSegment::read(File &file)
{
offset_t maxOffset = file.tell() + dataSize;
Element *element = nullptr;
std::unique_ptr<Element> element;
int i = 0;
int seekHeadIndex = -1;
while((element = findNextElement(file, maxOffset))) {
Id id = element->getId();
if(id == ElementIDs::MkSeekHead) {
if(id == Id::MkSeekHead) {
seekHeadIndex = i;
seekHead = static_cast<MkSeekHead *>(element);
seekHead = element_cast<Id::MkSeekHead>(std::move(element));
if(!seekHead->read(file))
return false;
}
else if(id == ElementIDs::MkInfo) {
info = static_cast<MkInfo *>(element);
else if(id == Id::MkInfo) {
info = element_cast<Id::MkInfo>(std::move(element));
if(!info->read(file))
return false;
}
else if(id == ElementIDs::MkTracks) {
tracks = static_cast<MkTracks *>(element);
else if(id == Id::MkTracks) {
tracks = element_cast<Id::MkTracks>(std::move(element));
if(!tracks->read(file))
return false;
}
else if(id == ElementIDs::MkTags) {
tags = static_cast<MkTags *>(element);
else if(id == Id::MkTags) {
tags = element_cast<Id::MkTags>(std::move(element));
if(!tags->read(file))
return false;
}
else if(id == ElementIDs::MkAttachments) {
attachments = static_cast<MkAttachments *>(element);
else if(id == Id::MkAttachments) {
attachments = element_cast<Id::MkAttachments>(std::move(element));
if(!attachments->read(file))
return false;
}
else {
if(id == ElementIDs::VoidElement
if(id == Id::VoidElement
&& seekHead
&& seekHeadIndex == i - 1)
seekHead->setPadding(element->getSize());
element->skipData(file);
delete element;
}
i++;
}
return true;
}
Matroska::Tag *EBML::MkSegment::parseTag()
std::unique_ptr<Matroska::Tag> EBML::MkSegment::parseTag()
{
return tags ? tags->parse() : nullptr;
}
Matroska::Attachments *EBML::MkSegment::parseAttachments()
std::unique_ptr<Matroska::Attachments> EBML::MkSegment::parseAttachments()
{
return attachments ? attachments->parse() : nullptr;
}
Matroska::SeekHead *EBML::MkSegment::parseSeekHead()
std::unique_ptr<Matroska::SeekHead> EBML::MkSegment::parseSeekHead()
{
return seekHead ? seekHead->parse() : nullptr;
}
Matroska::Segment *EBML::MkSegment::parseSegment()
std::unique_ptr<Matroska::Segment> EBML::MkSegment::parseSegment()
{
return new Matroska::Segment(sizeLength, dataSize, offset + idSize(id));
return std::make_unique<Matroska::Segment>(sizeLength, dataSize, offset + idSize(id));
}
void EBML::MkSegment::parseInfo(Matroska::Properties *properties)

View File

@ -23,6 +23,9 @@
#ifndef DO_NOT_DOCUMENT
#include "ebmlmasterelement.h"
#include "ebmlmktags.h"
#include "ebmlmkattachments.h"
#include "ebmlmkseekhead.h"
#include "ebmlmkinfo.h"
#include "ebmlmktracks.h"
#include "taglib.h"
@ -35,31 +38,32 @@ namespace TagLib {
class Segment;
}
namespace EBML {
class MkTags;
class MkAttachments;
class MkSeekHead;
class MkSegment : public MasterElement
{
public:
MkSegment(int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(ElementIDs::MkSegment, sizeLength, dataSize, offset)
MasterElement(Id::MkSegment, sizeLength, dataSize, offset)
{
}
MkSegment(Id, int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(Id::MkSegment, sizeLength, dataSize, offset)
{
}
~MkSegment() override;
bool read(File &file) override;
Matroska::Tag *parseTag();
Matroska::Attachments *parseAttachments();
Matroska::SeekHead *parseSeekHead();
Matroska::Segment *parseSegment();
std::unique_ptr<Matroska::Tag> parseTag();
std::unique_ptr<Matroska::Attachments> parseAttachments();
std::unique_ptr<Matroska::SeekHead> parseSeekHead();
std::unique_ptr<Matroska::Segment> parseSegment();
void parseInfo(Matroska::Properties *properties);
void parseTracks(Matroska::Properties *properties);
private:
MkTags *tags = nullptr;
MkAttachments *attachments = nullptr;
MkSeekHead *seekHead = nullptr;
MkInfo *info = nullptr;
MkTracks *tracks = nullptr;
std::unique_ptr<MkTags> tags;
std::unique_ptr<MkAttachments> attachments;
std::unique_ptr<MkSeekHead> seekHead;
std::unique_ptr<MkInfo> info;
std::unique_ptr<MkTracks> tracks;
};
}
}

View File

@ -28,39 +28,39 @@
using namespace TagLib;
Matroska::Tag *EBML::MkTags::parse()
std::unique_ptr<Matroska::Tag> EBML::MkTags::parse()
{
auto mTag = new Matroska::Tag();
auto mTag = std::make_unique<Matroska::Tag>();
mTag->setOffset(offset);
mTag->setSize(getSize());
mTag->setID(id);
mTag->setID(static_cast<Matroska::Element::ID>(id));
// Loop through each <Tag> element
for(auto tagsChild : elements) {
if(tagsChild->getId() != ElementIDs::MkTag)
for(const auto &tagsChild : elements) {
if(tagsChild->getId() != Id::MkTag)
continue;
auto tag = static_cast<MasterElement *>(tagsChild);
List<MasterElement *> simpleTags;
MasterElement *targets = nullptr;
auto tag = element_cast<Id::MkTag>(tagsChild);
List<const MasterElement *> simpleTags;
const MasterElement *targets = nullptr;
// Identify the <Targets> element and the <SimpleTag> elements
for(auto tagChild : *tag) {
for(const auto &tagChild : *tag) {
Id tagChildId = tagChild->getId();
if(!targets && tagChildId == ElementIDs::MkTagTargets)
targets = static_cast<MasterElement *>(tagChild);
else if(tagChildId == ElementIDs::MkSimpleTag)
simpleTags.append(static_cast<MasterElement *>(tagChild));
if(!targets && tagChildId == Id::MkTagTargets)
targets = element_cast<Id::MkTagTargets>(tagChild);
else if(tagChildId == Id::MkSimpleTag)
simpleTags.append(element_cast<Id::MkSimpleTag>(tagChild));
}
// Parse the <Targets> element
Matroska::SimpleTag::TargetTypeValue targetTypeValue = Matroska::SimpleTag::TargetTypeValue::None;
if(targets) {
for(auto targetsChild : *targets) {
for(const auto &targetsChild : *targets) {
Id id = targetsChild->getId();
if(id == ElementIDs::MkTagTargetTypeValue
if(id == Id::MkTagTargetTypeValue
&& targetTypeValue == Matroska::SimpleTag::TargetTypeValue::None) {
targetTypeValue = static_cast<Matroska::SimpleTag::TargetTypeValue>(
static_cast<UIntElement *>(targetsChild)->getValue()
element_cast<Id::MkTagTargetTypeValue>(targetsChild)->getValue()
);
}
}
@ -74,18 +74,18 @@ Matroska::Tag *EBML::MkTags::parse()
const String *language = nullptr;
bool defaultLanguageFlag = true;
for(auto simpleTagChild : *simpleTag) {
for(const auto &simpleTagChild : *simpleTag) {
Id id = simpleTagChild->getId();
if(id == ElementIDs::MkTagName && !tagName)
tagName = &(static_cast<UTF8StringElement *>(simpleTagChild)->getValue());
else if(id == ElementIDs::MkTagString && !tagValueString)
tagValueString = &(static_cast<UTF8StringElement *>(simpleTagChild)->getValue());
else if(id == ElementIDs::MkTagBinary && !tagValueBinary)
tagValueBinary = &(static_cast<BinaryElement *>(simpleTagChild)->getValue());
else if(id == ElementIDs::MkTagsTagLanguage && !language)
language = &(static_cast<Latin1StringElement *>(simpleTagChild)->getValue());
else if(id == ElementIDs::MkTagsLanguageDefault)
defaultLanguageFlag = static_cast<UIntElement *>(simpleTagChild)->getValue() ? true : false;
if(id == Id::MkTagName && !tagName)
tagName = &(element_cast<Id::MkTagName>(simpleTagChild)->getValue());
else if(id == Id::MkTagString && !tagValueString)
tagValueString = &(element_cast<Id::MkTagString>(simpleTagChild)->getValue());
else if(id == Id::MkTagBinary && !tagValueBinary)
tagValueBinary = &(element_cast<Id::MkTagBinary>(simpleTagChild)->getValue());
else if(id == Id::MkTagsTagLanguage && !language)
language = &(element_cast<Id::MkTagsTagLanguage>(simpleTagChild)->getValue());
else if(id == Id::MkTagsLanguageDefault)
defaultLanguageFlag = element_cast<Id::MkTagsLanguageDefault>(simpleTagChild)->getValue() ? true : false;
}
if(!tagName || (tagValueString && tagValueBinary) || (!tagValueString && !tagValueBinary))
continue;

View File

@ -36,15 +36,19 @@ namespace TagLib {
{
public:
MkTags(int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(ElementIDs::MkTags, sizeLength, dataSize, offset)
MasterElement(Id::MkTags, sizeLength, dataSize, offset)
{
}
MkTags(Id, int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(Id::MkTags, sizeLength, dataSize, offset)
{
}
MkTags() :
MasterElement(ElementIDs::MkTags, 0, 0, 0)
MasterElement(Id::MkTags, 0, 0, 0)
{
}
Matroska::Tag *parse();
std::unique_ptr<Matroska::Tag> parse();
};
}
}

View File

@ -36,29 +36,29 @@ void EBML::MkTracks::parse(Matroska::Properties *properties)
if(!properties)
return;
for(auto element : elements) {
if(element->getId() != ElementIDs::MkTrackEntry)
for(const auto &element : elements) {
if(element->getId() != Id::MkTrackEntry)
continue;
String codecId;
double samplingFrequency = 0.0;
unsigned long long bitDepth = 0;
unsigned long long channels = 0;
auto trackEntry = static_cast<MasterElement *>(element);
for(auto trackEntryChild : *trackEntry) {
auto trackEntry = element_cast<Id::MkTrackEntry>(element);
for(const auto &trackEntryChild : *trackEntry) {
Id trackEntryChildId = trackEntryChild->getId();
if(trackEntryChildId == ElementIDs::MkCodecID)
codecId = static_cast<Latin1StringElement *>(trackEntryChild)->getValue();
else if(trackEntryChildId == ElementIDs::MkAudio) {
auto audio = static_cast<MasterElement *>(trackEntryChild);
for(auto audioChild : *audio) {
if(trackEntryChildId == Id::MkCodecID)
codecId = element_cast<Id::MkCodecID>(trackEntryChild)->getValue();
else if(trackEntryChildId == Id::MkAudio) {
auto audio = element_cast<Id::MkAudio>(trackEntryChild);
for(const auto &audioChild : *audio) {
Id audioChildId = audioChild->getId();
if(audioChildId == ElementIDs::MkSamplingFrequency)
samplingFrequency = static_cast<FloatElement *>(audioChild)->getValueAsDouble();
else if(audioChildId == ElementIDs::MkBitDepth)
bitDepth = static_cast<UIntElement *>(audioChild)->getValue();
else if(audioChildId == ElementIDs::MkChannels)
channels = static_cast<UIntElement *>(audioChild)->getValue();
if(audioChildId == Id::MkSamplingFrequency)
samplingFrequency = element_cast<Id::MkSamplingFrequency>(audioChild)->getValueAsDouble();
else if(audioChildId == Id::MkBitDepth)
bitDepth = element_cast<Id::MkBitDepth>(audioChild)->getValue();
else if(audioChildId == Id::MkChannels)
channels = element_cast<Id::MkChannels>(audioChild)->getValue();
}
}
}

View File

@ -40,11 +40,15 @@ namespace TagLib {
{
public:
MkTracks(int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(ElementIDs::MkTracks, sizeLength, dataSize, offset)
MasterElement(Id::MkTracks, sizeLength, dataSize, offset)
{
}
MkTracks(Id, int sizeLength, offset_t dataSize, offset_t offset) :
MasterElement(Id::MkTracks, sizeLength, dataSize, offset)
{
}
MkTracks() :
MasterElement(ElementIDs::MkTracks, 0, 0, 0)
MasterElement(Id::MkTracks, 0, 0, 0)
{
}
void parse(Matroska::Properties *properties);

View File

@ -37,6 +37,10 @@ namespace TagLib {
Element(id, sizeLength, dataSize)
{
}
StringElement(Id id, int sizeLength, offset_t dataSize, offset_t) :
Element(id, sizeLength, dataSize)
{
}
explicit StringElement(Id id) :
Element(id, 0, 0)

View File

@ -35,6 +35,10 @@ namespace TagLib {
Element(id, sizeLength, dataSize)
{
}
UIntElement(Id id, int sizeLength, offset_t dataSize, offset_t) :
Element(id, sizeLength, dataSize)
{
}
explicit UIntElement(Id id) :
UIntElement(id, 0, 0)

View File

@ -30,21 +30,20 @@
using namespace TagLib;
EBML::Element *EBML::findElement(File &file, Element::Id id, offset_t maxOffset)
std::unique_ptr<EBML::Element> EBML::findElement(File &file, Element::Id id, offset_t maxOffset)
{
Element *element = nullptr;
std::unique_ptr<Element> element;
while(file.tell() < maxOffset) {
element = Element::factory(file);
if(!element || element->getId() == id)
return element;
element->skipData(file);
delete element;
element = nullptr;
element.reset();
}
return element;
}
EBML::Element *EBML::findNextElement(File &file, offset_t maxOffset)
std::unique_ptr<EBML::Element> EBML::findNextElement(File &file, offset_t maxOffset)
{
return file.tell() < maxOffset ? Element::factory(file) : nullptr;
}

View File

@ -59,8 +59,8 @@ namespace TagLib {
std::pair<int, T> readVINT(File &file);
template <typename T>
std::pair<int, T> parseVINT(const ByteVector &buffer);
Element *findElement(File &file, Element::Id id, offset_t maxOffset);
Element *findNextElement(File &file, offset_t maxOffset);
std::unique_ptr<Element> findElement(File &file, Element::Id id, offset_t maxOffset);
std::unique_ptr<Element> findNextElement(File &file, offset_t maxOffset);
ByteVector renderVINT(uint64_t number, int minSizeLength);
unsigned long long randomUID();
@ -82,11 +82,12 @@ namespace TagLib {
constexpr int idSize(Element::Id id)
{
if(id <= 0xFF)
auto uintId = static_cast<unsigned int>(id);
if(uintId <= 0xFF)
return 1;
else if(id <= 0xFFFF)
else if(uintId <= 0xFFFF)
return 2;
else if(id <= 0xFFFFFF)
else if(uintId <= 0xFFFFFF)
return 3;
else
return 4;

View File

@ -33,10 +33,13 @@ namespace TagLib {
{
public:
VoidElement(int sizeLength, offset_t dataSize) :
Element(ElementIDs::VoidElement, sizeLength, dataSize)
Element(Id::VoidElement, sizeLength, dataSize)
{}
VoidElement(Id, int sizeLength, offset_t dataSize, offset_t) :
Element(Id::VoidElement, sizeLength, dataSize)
{}
VoidElement() :
Element(ElementIDs::VoidElement, 0, 0)
Element(Id::VoidElement, 0, 0)
{}
ByteVector render() override;
offset_t getTargetSize() const;

View File

@ -1,5 +1,5 @@
#include <memory>
#include "matroskaattachments.h"
#include <memory>
#include "matroskaattachedfile.h"
#include "ebmlmkattachments.h"
#include "ebmlmasterelement.h"
@ -22,7 +22,7 @@ public:
};
Matroska::Attachments::Attachments() :
Element(ElementIDs::MkAttachments),
Element(static_cast<ID>(EBML::Element::Id::MkAttachments)),
d(std::make_unique<AttachmentsPrivate>())
{
d->files.setAutoDelete(true);
@ -57,40 +57,40 @@ bool Matroska::Attachments::render()
{
EBML::MkAttachments attachments;
for(const auto attachedFile : d->files) {
auto attachedFileElement = new EBML::MasterElement(EBML::ElementIDs::MkAttachedFile);
auto attachedFileElement = EBML::make_unique_element<EBML::Element::Id::MkAttachedFile>();
// Filename
auto fileNameElement = new EBML::UTF8StringElement(EBML::ElementIDs::MkAttachedFileName);
auto fileNameElement = EBML::make_unique_element<EBML::Element::Id::MkAttachedFileName>();
fileNameElement->setValue(attachedFile->fileName());
attachedFileElement->appendElement(fileNameElement);
attachedFileElement->appendElement(std::move(fileNameElement));
// Media/MIME type
auto mediaTypeElement = new EBML::Latin1StringElement(EBML::ElementIDs::MkAttachedFileMediaType);
auto mediaTypeElement = EBML::make_unique_element<EBML::Element::Id::MkAttachedFileMediaType>();
mediaTypeElement->setValue(attachedFile->mediaType());
attachedFileElement->appendElement(mediaTypeElement);
attachedFileElement->appendElement(std::move(mediaTypeElement));
// Description
const String &description = attachedFile->description();
if(!description.isEmpty()) {
auto descriptionElement = new EBML::UTF8StringElement(EBML::ElementIDs::MkAttachedFileDescription);
auto descriptionElement = EBML::make_unique_element<EBML::Element::Id::MkAttachedFileDescription>();
descriptionElement->setValue(description);
attachedFileElement->appendElement(descriptionElement);
attachedFileElement->appendElement(std::move(descriptionElement));
}
// Data
auto dataElement = new EBML::BinaryElement(EBML::ElementIDs::MkAttachedFileData);
auto dataElement = EBML::make_unique_element<EBML::Element::Id::MkAttachedFileData>();
dataElement->setValue(attachedFile->data());
attachedFileElement->appendElement(dataElement);
attachedFileElement->appendElement(std::move(dataElement));
// UID
auto uidElement = new EBML::UIntElement(EBML::ElementIDs::MkAttachedFileUID);
auto uidElement = EBML::make_unique_element<EBML::Element::Id::MkAttachedFileUID>();
AttachedFile::UID uid = attachedFile->uid();
if(!uid)
uid = EBML::randomUID();
uidElement->setValue(uid);
attachedFileElement->appendElement(uidElement);
attachedFileElement->appendElement(std::move(uidElement));
attachments.appendElement(attachedFileElement);
attachments.appendElement(std::move(attachedFileElement));
}
auto beforeSize = size();

View File

@ -30,48 +30,47 @@
using namespace TagLib;
Matroska::Cues::Cues() :
Element(ElementIDs::MkCues)
Element(static_cast<ID>(EBML::Element::Id::MkCues))
{
cuePoints.setAutoDelete(true);
}
ByteVector Matroska::Cues::renderInternal()
{
EBML::MkCues cues;
for(auto &cuePoint : cuePoints) {
auto cuePointElement = new EBML::MasterElement(EBML::ElementIDs::MkCuePoint);
auto timestamp = new EBML::UIntElement(EBML::ElementIDs::MkCueTime);
for(const auto &cuePoint : cuePoints) {
auto cuePointElement = EBML::make_unique_element<EBML::Element::Id::MkCuePoint>();
auto timestamp = EBML::make_unique_element<EBML::Element::Id::MkCueTime>();
timestamp->setValue(cuePoint->getTime());
cuePointElement->appendElement(timestamp);
cuePointElement->appendElement(std::move(timestamp));
auto trackList = cuePoint->cueTrackList();
for(auto &cueTrack : trackList) {
auto cueTrackElement = new EBML::MasterElement(EBML::ElementIDs::MkCueTrackPositions);
const auto &trackList = cuePoint->cueTrackList();
for(const auto &cueTrack : trackList) {
auto cueTrackElement = EBML::make_unique_element<EBML::Element::Id::MkCueTrackPositions>();
// Track number
auto trackNumber = new EBML::UIntElement(EBML::ElementIDs::MkCueTrack);
auto trackNumber = EBML::make_unique_element<EBML::Element::Id::MkCueTrack>();
trackNumber->setValue(cueTrack->getTrackNumber());
cueTrackElement->appendElement(trackNumber);
cueTrackElement->appendElement(std::move(trackNumber));
// Cluster position
auto clusterPosition = new EBML::UIntElement(EBML::ElementIDs::MkCueClusterPosition);
auto clusterPosition = EBML::make_unique_element<EBML::Element::Id::MkCueClusterPosition>();
clusterPosition->setValue(cueTrack->getClusterPosition());
cueTrackElement->appendElement(clusterPosition);
cueTrackElement->appendElement(std::move(clusterPosition));
// Todo - other elements
// Reference times
auto referenceTimes = cueTrack->referenceTimes();
if(!referenceTimes.isEmpty()) {
auto cueReference = new EBML::MasterElement(EBML::ElementIDs::MkCueReference);
auto cueReference = EBML::make_unique_element<EBML::Element::Id::MkCueReference>();
for(auto reference : referenceTimes) {
auto refTime = new EBML::UIntElement(EBML::ElementIDs::MkCueRefTime);
auto refTime = EBML::make_unique_element<EBML::Element::Id::MkCueRefTime>();
refTime->setValue(reference);
cueReference->appendElement(refTime);
cueReference->appendElement(std::move(refTime));
}
cueTrackElement->appendElement(cueReference);
cueTrackElement->appendElement(std::move(cueReference));
}
cuePointElement->appendElement(cueTrackElement);
cuePointElement->appendElement(std::move(cueTrackElement));
}
}
return cues.render();
@ -90,38 +89,47 @@ bool Matroska::Cues::render()
bool Matroska::Cues::sizeChanged(Element &caller, offset_t delta)
{
offset_t offset = caller.offset();
for(auto cuePoint : cuePoints)
for(auto &cuePoint : cuePoints)
needsRender |= cuePoint->adjustOffset(offset, delta);
return true;
}
bool Matroska::Cues::isValid(TagLib::File &file, offset_t segmentDataOffset) const
{
for(const auto cuePoint : cuePoints) {
for(const auto &cuePoint : cuePoints) {
if(!cuePoint->isValid(file, segmentDataOffset))
return false;
}
return true;
}
void Matroska::Cues::addCuePoint(std::unique_ptr<CuePoint> &&cuePoint)
{
cuePoints.push_back(std::move(cuePoint));
}
Matroska::CuePoint::CuePoint()
{
cueTracks.setAutoDelete(true);
}
bool Matroska::CuePoint::isValid(TagLib::File &file, offset_t segmentDataOffset) const
{
for(const auto track : cueTracks) {
for(const auto &track : cueTracks) {
if(!track->isValid(file, segmentDataOffset))
return false;
}
return true;
}
void Matroska::CuePoint::addCueTrack(std::unique_ptr<CueTrack> &&cueTrack)
{
cueTracks.push_back(std::move(cueTrack));
}
bool Matroska::CuePoint::adjustOffset(offset_t offset, offset_t delta)
{
bool ret = false;
for(auto cueTrack : cueTracks)
for(auto &cueTrack : cueTracks)
ret |= cueTrack->adjustOffset(offset, delta);
return ret;
@ -138,13 +146,13 @@ bool Matroska::CueTrack::isValid(TagLib::File &file, offset_t segmentDataOffset)
return false;
}
file.seek(segmentDataOffset + clusterPosition);
if(EBML::Element::readId(file) != EBML::ElementIDs::MkCluster) {
if(EBML::Element::readId(file) != static_cast<unsigned int>(EBML::Element::Id::MkCluster)) {
debug("No cluster found at position");
return false;
}
if(codecState) {
file.seek(segmentDataOffset + codecState);
if(EBML::Element::readId(file) != EBML::ElementIDs::MkCodecState) {
if(EBML::Element::readId(file) != static_cast<unsigned int>(EBML::Element::Id::MkCodecState)) {
debug("No codec state found at position");
return false;
}

View File

@ -37,12 +37,12 @@ namespace TagLib {
class Cues : public Element
{
public:
using CuePointList = List<CuePoint *>;
using CuePointList = std::list<std::unique_ptr<CuePoint>>;
Cues();
~Cues() override = default;
bool isValid(File &file, offset_t segmentDataOffset) const;
void addCuePoint(CuePoint *cuePoint) { cuePoints.append(cuePoint); }
CuePointList cuePointList() { return cuePoints; }
void addCuePoint(std::unique_ptr<CuePoint> &&cuePoint);
const CuePointList &cuePointList() { return cuePoints; }
bool sizeChanged(Element &caller, offset_t delta) override;
bool render() override;
@ -51,19 +51,19 @@ namespace TagLib {
ByteVector renderInternal();
bool needsRender = false;
List<CuePoint *> cuePoints;
CuePointList cuePoints;
};
class CuePoint
{
public:
using CueTrackList = List<CueTrack *>;
using CueTrackList = std::list<std::unique_ptr<CueTrack>>;
using Time = unsigned long long;
CuePoint();
~CuePoint() = default;
bool isValid(File &file, offset_t segmentDataOffset) const;
void addCueTrack(CueTrack *cueTrack) { cueTracks.append(cueTrack); }
CueTrackList cueTrackList() const { return cueTracks; }
void addCueTrack(std::unique_ptr<CueTrack> &&cueTrack);
const CueTrackList &cueTrackList() const { return cueTracks; }
void setTime(Time time) { this->time = time; }
Time getTime() const { return time; }
bool adjustOffset(offset_t offset, offset_t delta);
@ -93,7 +93,7 @@ namespace TagLib {
void setDuration(unsigned long long duration) { this->duration = duration; }
unsigned long long getDuration() const { return duration; }
void addReferenceTime(unsigned long long refTime) { refTimes.append(refTime); }
ReferenceTimeList referenceTimes() const { return refTimes; }
const ReferenceTimeList &referenceTimes() const { return refTimes; }
bool adjustOffset(offset_t offset, offset_t delta);
private:

View File

@ -65,13 +65,6 @@ namespace TagLib {
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<ElementPrivate> e;
};
namespace ElementIDs {
inline constexpr Element::ID MkTags = 0x1254C367;
inline constexpr Element::ID MkAttachments = 0x1941A469;
inline constexpr Element::ID MkSeekHead = 0x114D9B74;
inline constexpr Element::ID MkSegment = 0x18538067;
inline constexpr Element::ID MkCues = 0x1C53BB6B;
}
}
}

View File

@ -39,20 +39,15 @@ class Matroska::File::FilePrivate
{
public:
FilePrivate() = default;
~FilePrivate()
{
delete tag;
delete attachments;
delete seekHead;
delete segment;
}
~FilePrivate() = default;
FilePrivate(const FilePrivate &) = delete;
FilePrivate &operator=(const FilePrivate &) = delete;
Tag *tag = nullptr;
Attachments *attachments = nullptr;
SeekHead *seekHead = nullptr;
Segment *segment = nullptr;
std::unique_ptr<Tag> tag;
std::unique_ptr<Attachments> attachments;
std::unique_ptr<SeekHead> seekHead;
std::unique_ptr<Segment> segment;
std::unique_ptr<Properties> properties;
};
@ -110,24 +105,16 @@ Tag *Matroska::File::tag() const
Matroska::Tag *Matroska::File::tag(bool create) const
{
if(d->tag)
return d->tag;
else {
if(create)
d->tag = new Tag();
return d->tag;
}
if(!d->tag && create)
d->tag = std::make_unique<Tag>();
return d->tag.get();
}
Matroska::Attachments *Matroska::File::attachments(bool create) const
{
if(d->attachments)
return d->attachments;
else {
if(create)
d->attachments = new Attachments();
return d->attachments;
}
if(!d->attachments && create)
d->attachments = std::make_unique<Attachments>();
return d->attachments.get();
}
void Matroska::File::read(bool readProperties, Properties::ReadStyle)
@ -136,7 +123,7 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle)
// 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::Element::Id::EBMLHeader) {
debug("Failed to find EBML head");
setValid(false);
return;
@ -145,8 +132,8 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle)
// Find the Matroska segment in the file
std::unique_ptr<EBML::MkSegment> segment(
static_cast<EBML::MkSegment *>(
EBML::findElement(*this, EBML::ElementIDs::MkSegment, fileLength - tell())
EBML::element_cast<EBML::Element::Id::MkSegment>(
EBML::findElement(*this, EBML::Element::Id::MkSegment, fileLength - tell())
)
);
if(!segment) {
@ -193,8 +180,8 @@ bool Matroska::File::save()
// List of all possible elements we can write
List<Element *> elements {
d->attachments,
d->tag
d->attachments.get(),
d->tag.get()
};
/* Build render list. New elements will be added
@ -235,15 +222,15 @@ bool Matroska::File::save()
for(auto it2 = std::next(it); it2 != renderList.end(); ++it2)
(*it)->addSizeListener(*it2);
if(d->seekHead)
(*it)->addSizeListener(d->seekHead);
(*it)->addSizeListener(d->segment);
(*it)->addSizeListener(d->seekHead.get());
(*it)->addSizeListener(d->segment.get());
}
if(d->seekHead) {
d->seekHead->addSizeListeners(renderList);
renderList.append(d->seekHead);
renderList.append(d->seekHead.get());
}
d->segment->addSizeListeners(renderList);
renderList.append(d->segment);
renderList.append(d->segment.get());
// Render the elements
for(auto element : renderList) {

View File

@ -27,6 +27,11 @@
using namespace TagLib;
Matroska::SeekHead::SeekHead() :
Element(static_cast<ID>(EBML::Element::Id::MkSeekHead))
{
}
void Matroska::SeekHead::addEntry(const Element &element)
{
entries.append({element.id(), element.offset()});
@ -46,16 +51,16 @@ ByteVector Matroska::SeekHead::renderInternal()
EBML::MkSeekHead seekHead;
seekHead.setMinRenderSize(beforeSize);
for(const auto &[id, position] : entries) {
auto seekElement = new EBML::MasterElement(EBML::ElementIDs::MkSeek);
auto idElement = new EBML::BinaryElement(EBML::ElementIDs::MkSeekID);
auto seekElement = EBML::make_unique_element<EBML::Element::Id::MkSeek>();
auto idElement = EBML::make_unique_element<EBML::Element::Id::MkSeekID>();
idElement->setValue(ByteVector::fromUInt(id, true));
seekElement->appendElement(idElement);
seekElement->appendElement(std::move(idElement));
auto positionElement = new EBML::UIntElement(EBML::ElementIDs::MkSeekPosition);
auto positionElement = EBML::make_unique_element<EBML::Element::Id::MkSeekPosition>();
positionElement->setValue(static_cast<unsigned long long>(position));
seekElement->appendElement(positionElement);
seekElement->appendElement(std::move(positionElement));
seekHead.appendElement(seekElement);
seekHead.appendElement(std::move(seekElement));
}
return seekHead.render();
}
@ -94,7 +99,7 @@ void Matroska::SeekHead::sort()
bool Matroska::SeekHead::sizeChanged(Element &caller, offset_t delta)
{
ID callerID = caller.id();
if(callerID == ElementIDs::MkSegment) {
if(callerID == static_cast<ID>(EBML::Element::Id::MkSegment)) {
adjustOffset(delta);
return true;
}

View File

@ -32,7 +32,7 @@ namespace TagLib {
class SeekHead : public Element
{
public:
SeekHead() : Element(ElementIDs::MkSeekHead) {}
SeekHead();
~SeekHead() override = default;
void addEntry(const Element &element);
void addEntry(ID id, offset_t offset);

View File

@ -23,6 +23,14 @@
using namespace TagLib;
Matroska::Segment::Segment(offset_t sizeLength, offset_t dataSize, offset_t lengthOffset) :
Element(static_cast<ID>(EBML::Element::Id::MkSegment)),
sizeLength(sizeLength), dataSize(dataSize)
{
setOffset(lengthOffset);
setSize(sizeLength);
}
bool Matroska::Segment::render()
{
auto data = EBML::renderVINT(dataSize, static_cast<int>(sizeLength));

View File

@ -28,13 +28,7 @@ namespace TagLib::Matroska {
class Segment : public Element
{
public:
Segment(offset_t sizeLength, offset_t dataSize, offset_t lengthOffset) :
Element(ElementIDs::MkSegment), sizeLength(sizeLength), dataSize(dataSize)
{
setOffset(lengthOffset);
setSize(sizeLength);
}
Segment(offset_t sizeLength, offset_t dataSize, offset_t lengthOffset);
~Segment() override = default;
bool render() override;
bool sizeChanged(Element &caller, offset_t delta) override;

View File

@ -95,7 +95,7 @@ public:
};
Matroska::Tag::Tag() :
Element(ElementIDs::MkTags),
Element(static_cast<ID>(EBML::Element::Id::MkTags)),
d(std::make_unique<TagPrivate>())
{
d->tags.setAutoDelete(true);
@ -241,52 +241,52 @@ bool Matroska::Tag::render()
for(auto list : targetList) {
auto frontTag = list->front();
auto targetTypeValue = frontTag->targetTypeValue();
auto tag = new EBML::MasterElement(EBML::ElementIDs::MkTag);
auto tag = EBML::make_unique_element<EBML::Element::Id::MkTag>();
// Build <Tag Targets> element
auto targets = new EBML::MasterElement(EBML::ElementIDs::MkTagTargets);
auto targets = EBML::make_unique_element<EBML::Element::Id::MkTagTargets>();
if(targetTypeValue != SimpleTag::TargetTypeValue::None) {
auto element = new EBML::UIntElement(EBML::ElementIDs::MkTagTargetTypeValue);
auto element = EBML::make_unique_element<EBML::Element::Id::MkTagTargetTypeValue>();
element->setValue(static_cast<unsigned int>(targetTypeValue));
targets->appendElement(element);
targets->appendElement(std::move(element));
}
tag->appendElement(targets);
tag->appendElement(std::move(targets));
// Build <Simple Tag> element
for(auto simpleTag : *list) {
auto t = new EBML::MasterElement(EBML::ElementIDs::MkSimpleTag);
auto tagName = new EBML::UTF8StringElement(EBML::ElementIDs::MkTagName);
auto t = EBML::make_unique_element<EBML::Element::Id::MkSimpleTag>();
auto tagName = EBML::make_unique_element<EBML::Element::Id::MkTagName>();
tagName->setValue(simpleTag->name());
t->appendElement(tagName);
t->appendElement(std::move(tagName));
// Tag Value
SimpleTagString *tStr = nullptr;
SimpleTagBinary *tBin = nullptr;
if((tStr = dynamic_cast<SimpleTagString *>(simpleTag))) {
auto tagValue = new EBML::UTF8StringElement(EBML::ElementIDs::MkTagString);
auto tagValue = EBML::make_unique_element<EBML::Element::Id::MkTagString>();
tagValue->setValue(tStr->value());
t->appendElement(tagValue);
t->appendElement(std::move(tagValue));
}
else if((tBin = dynamic_cast<SimpleTagBinary *>(simpleTag))) {
auto tagValue = new EBML::BinaryElement(EBML::ElementIDs::MkTagBinary);
auto tagValue = EBML::make_unique_element<EBML::Element::Id::MkTagBinary>();
tagValue->setValue(tBin->value());
t->appendElement(tagValue);
t->appendElement(std::move(tagValue));
}
// Language
auto language = new EBML::Latin1StringElement(EBML::ElementIDs::MkTagsTagLanguage);
auto language = EBML::make_unique_element<EBML::Element::Id::MkTagsTagLanguage>();
const String &lang = simpleTag->language();
language->setValue(!lang.isEmpty() ? lang : "und");
t->appendElement(language);
t->appendElement(std::move(language));
// Default language flag
auto dlf = new EBML::UIntElement(EBML::ElementIDs::MkTagsLanguageDefault);
auto dlf = EBML::make_unique_element<EBML::Element::Id::MkTagsLanguageDefault>();
dlf->setValue(simpleTag->defaultLanguageFlag() ? 1 : 0);
t->appendElement(dlf);
t->appendElement(std::move(dlf));
tag->appendElement(t);
tag->appendElement(std::move(t));
}
tags.appendElement(tag);
tags.appendElement(std::move(tag));
}
auto data = tags.render();