mirror of
https://github.com/taglib/taglib.git
synced 2026-04-02 04:02:43 -04:00
Replace raw pointers by smart pointers
Also improve type safety and consistency.
This commit is contained in:
@ -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)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
Reference in New Issue
Block a user