mirror of
https://github.com/taglib/taglib.git
synced 2026-04-03 04:32:45 -04:00
Fix seekhead
This commit is contained in:
committed by
Urs Fleisch
parent
6d019a894c
commit
975eaac3ca
@ -230,15 +230,19 @@ if(WITH_SHORTEN)
|
||||
endif()
|
||||
|
||||
set(tag_PRIVATE_HDRS
|
||||
matroska/matroskaseekhead.h
|
||||
matroska/matroskasegment.h
|
||||
matroska/ebml/ebmlbinaryelement.h
|
||||
matroska/ebml/ebmlelement.h
|
||||
matroska/ebml/ebmlmasterelement.h
|
||||
matroska/ebml/ebmlmkattachments.h
|
||||
matroska/ebml/ebmlmkseekhead.h
|
||||
matroska/ebml/ebmlmksegment.h
|
||||
matroska/ebml/ebmlmktags.h
|
||||
matroska/ebml/ebmlstringelement.h
|
||||
matroska/ebml/ebmluintelement.h
|
||||
matroska/ebml/ebmlutils.h
|
||||
matroska/ebml/ebmlvoidelement.h
|
||||
)
|
||||
|
||||
set(tag_HDRS ${tag_PUBLIC_HDRS} ${tag_PRIVATE_HDRS})
|
||||
@ -248,6 +252,8 @@ set(matroska_SRCS
|
||||
matroska/matroskaattachments.cpp
|
||||
matroska/matroskaelement.cpp
|
||||
matroska/matroskafile.cpp
|
||||
matroska/matroskaseekhead.cpp
|
||||
matroska/matroskasegment.cpp
|
||||
matroska/matroskasimpletag.cpp
|
||||
matroska/matroskatag.cpp
|
||||
)
|
||||
@ -257,11 +263,13 @@ set(ebml_SRCS
|
||||
matroska/ebml/ebmlelement.cpp
|
||||
matroska/ebml/ebmlmasterelement.cpp
|
||||
matroska/ebml/ebmlmkattachments.cpp
|
||||
matroska/ebml/ebmlmkseekhead.cpp
|
||||
matroska/ebml/ebmlmksegment.cpp
|
||||
matroska/ebml/ebmlmktags.cpp
|
||||
matroska/ebml/ebmlstringelement.cpp
|
||||
matroska/ebml/ebmluintelement.cpp
|
||||
matroska/ebml/ebmlutils.cpp
|
||||
matroska/ebml/ebmlvoidelement.cpp
|
||||
)
|
||||
|
||||
set(mpeg_SRCS
|
||||
|
||||
@ -19,8 +19,10 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlelement.h"
|
||||
#include "ebmlvoidelement.h"
|
||||
#include "ebmlmasterelement.h"
|
||||
#include "ebmlbinaryelement.h"
|
||||
#include "ebmlmkseekhead.h"
|
||||
#include "ebmlmksegment.h"
|
||||
#include "ebmlmktags.h"
|
||||
#include "ebmlmkattachments.h"
|
||||
@ -68,6 +70,7 @@ EBML::Element* EBML::Element::factory(File &file)
|
||||
case ElementIDs::MkTagTargets:
|
||||
case ElementIDs::MkSimpleTag:
|
||||
case ElementIDs::MkAttachedFile:
|
||||
case ElementIDs::MkSeek:
|
||||
return new MasterElement(id, sizeLength, dataSize, offset);
|
||||
|
||||
case ElementIDs::MkTagName:
|
||||
@ -82,10 +85,18 @@ EBML::Element* EBML::Element::factory(File &file)
|
||||
|
||||
case ElementIDs::MkTagTargetTypeValue:
|
||||
case ElementIDs::MkAttachedFileUID:
|
||||
case ElementIDs::MkSeekPosition:
|
||||
return new UIntElement(id, sizeLength, dataSize);
|
||||
|
||||
case ElementIDs::MkAttachedFileData:
|
||||
case ElementIDs::MkSeekID:
|
||||
return new BinaryElement(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);
|
||||
|
||||
@ -43,6 +43,7 @@ namespace TagLib {
|
||||
void skipData(File &file);
|
||||
Id getId() const { return id; }
|
||||
offset_t headSize() const;
|
||||
offset_t getSize() const { return headSize() + dataSize; }
|
||||
int getSizeLength() const { return sizeLength; }
|
||||
int64_t getDataSize() const { return dataSize; }
|
||||
ByteVector renderId();
|
||||
@ -58,6 +59,7 @@ namespace TagLib {
|
||||
|
||||
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;
|
||||
@ -76,6 +78,10 @@ namespace TagLib {
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlmasterelement.h"
|
||||
#include "ebmlvoidelement.h"
|
||||
#include "ebmlutils.h"
|
||||
#include "matroskafile.h"
|
||||
|
||||
@ -55,5 +56,10 @@ ByteVector EBML::MasterElement::render()
|
||||
dataSize = data.size();
|
||||
buffer.append(renderVINT(dataSize, 0));
|
||||
buffer.append(data);
|
||||
if (minRenderSize) {
|
||||
auto bufferSize = buffer.size();
|
||||
if(minRenderSize >= (bufferSize + MIN_VOID_ELEMENT_SIZE))
|
||||
buffer.append(VoidElement::renderSize(minRenderSize - bufferSize));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@ -41,7 +41,6 @@ namespace TagLib {
|
||||
{}
|
||||
~MasterElement() override;
|
||||
offset_t getOffset() const { return offset; }
|
||||
offset_t getSize() const { return headSize() + dataSize; }
|
||||
bool read(File &file) override;
|
||||
ByteVector render() override;
|
||||
void appendElement(Element *element) { elements.append(element); }
|
||||
@ -49,9 +48,16 @@ namespace TagLib {
|
||||
List<Element*>::Iterator end () { return elements.end(); }
|
||||
List<Element*>::ConstIterator cbegin () const { return elements.cbegin(); }
|
||||
List<Element*>::ConstIterator 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; }
|
||||
void setMinRenderSize(offset_t minRenderSize) { this->minRenderSize = minRenderSize; }
|
||||
|
||||
|
||||
protected:
|
||||
offset_t offset;
|
||||
offset_t padding = 0;
|
||||
offset_t minRenderSize = 0;
|
||||
List<Element*> elements;
|
||||
};
|
||||
|
||||
|
||||
59
taglib/matroska/ebml/ebmlmkseekhead.cpp
Normal file
59
taglib/matroska/ebml/ebmlmkseekhead.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlmkseekhead.h"
|
||||
#include "matroskaseekhead.h"
|
||||
#include "ebmluintelement.h"
|
||||
#include "ebmlbinaryelement.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
Matroska::SeekHead* EBML::MkSeekHead::parse()
|
||||
{
|
||||
auto seekHead = new Matroska::SeekHead();
|
||||
seekHead->setOffset(offset);
|
||||
seekHead->setSize(getSize() + padding);
|
||||
|
||||
for(auto element : elements) {
|
||||
if(element->getId() != ElementIDs::MkSeek)
|
||||
continue;
|
||||
auto seekElement = static_cast<MasterElement*>(element);
|
||||
Matroska::Element::ID entryId = 0;
|
||||
offset_t offset = 0;
|
||||
for(auto seekElementChild : *seekElement) {
|
||||
Id id = seekElementChild->getId();
|
||||
if(id == ElementIDs::MkSeekID && !entryId) {
|
||||
auto data = static_cast<BinaryElement*>(seekElementChild)->getValue();
|
||||
if(data.size() == 4)
|
||||
entryId = data.toUInt(true);
|
||||
}
|
||||
else if(id == ElementIDs::MkSeekPosition && !offset)
|
||||
offset = static_cast<UIntElement*>(seekElementChild)->getValue();
|
||||
}
|
||||
if(entryId && offset)
|
||||
seekHead->addEntry(entryId, offset);
|
||||
else {
|
||||
delete seekHead;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return seekHead;
|
||||
}
|
||||
49
taglib/matroska/ebml/ebmlmkseekhead.h
Normal file
49
taglib/matroska/ebml/ebmlmkseekhead.h
Normal file
@ -0,0 +1,49 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlmasterelement.h"
|
||||
#include "taglib.h"
|
||||
|
||||
#ifndef TAGLIB_EBMLMKSEEKHEAD_H
|
||||
#define TAGLIB_EBMLMKSEEKHEAD_H
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
namespace TagLib {
|
||||
namespace Matroska {
|
||||
class SeekHead;
|
||||
}
|
||||
namespace EBML {
|
||||
class MkSeekHead : public MasterElement
|
||||
{
|
||||
public:
|
||||
MkSeekHead(int sizeLength, offset_t dataSize, offset_t offset)
|
||||
: MasterElement(ElementIDs::MkSeekHead, sizeLength, dataSize, offset)
|
||||
{}
|
||||
MkSeekHead()
|
||||
: MasterElement(ElementIDs::MkSeekHead, 0, 0, 0)
|
||||
{}
|
||||
|
||||
Matroska::SeekHead* parse();
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@ -21,10 +21,13 @@
|
||||
#include "ebmlmksegment.h"
|
||||
#include "ebmlmktags.h"
|
||||
#include "ebmlmkattachments.h"
|
||||
#include "ebmlmkseekhead.h"
|
||||
#include "ebmlutils.h"
|
||||
#include "matroskafile.h"
|
||||
#include "matroskatag.h"
|
||||
#include "matroskaattachments.h"
|
||||
#include "matroskaseekhead.h"
|
||||
#include "matroskasegment.h"
|
||||
#include "tutils.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tdebug.h"
|
||||
@ -35,16 +38,24 @@ EBML::MkSegment::~MkSegment()
|
||||
{
|
||||
delete tags;
|
||||
delete attachments;
|
||||
delete seekHead;
|
||||
}
|
||||
|
||||
bool EBML::MkSegment::read(File &file)
|
||||
{
|
||||
offset_t maxOffset = file.tell() + dataSize;
|
||||
EBML::Element *element = nullptr;
|
||||
|
||||
int i = 0;
|
||||
int seekHeadIndex = -1;
|
||||
while((element = findNextElement(file, maxOffset))) {
|
||||
Id id = element->getId();
|
||||
if(id == ElementIDs::MkTags) {
|
||||
if(id == ElementIDs::MkSeekHead) {
|
||||
seekHeadIndex = i;
|
||||
seekHead = static_cast<MkSeekHead*>(element);
|
||||
if(!seekHead->read(file))
|
||||
return false;
|
||||
}
|
||||
else if(id == ElementIDs::MkTags) {
|
||||
tags = static_cast<MkTags*>(element);
|
||||
if(!tags->read(file))
|
||||
return false;
|
||||
@ -55,9 +66,15 @@ bool EBML::MkSegment::read(File &file)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if(id == ElementIDs::VoidElement
|
||||
&& seekHead
|
||||
&& seekHeadIndex == (i - 1))
|
||||
seekHead->setPadding(element->getSize());
|
||||
|
||||
element->skipData(file);
|
||||
delete element;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -71,3 +88,13 @@ Matroska::Attachments* EBML::MkSegment::parseAttachments()
|
||||
{
|
||||
return attachments ? attachments->parse() : nullptr;
|
||||
}
|
||||
|
||||
Matroska::SeekHead* EBML::MkSegment::parseSeekHead()
|
||||
{
|
||||
return seekHead ? seekHead->parse() : nullptr;
|
||||
}
|
||||
|
||||
Matroska::Segment* EBML::MkSegment::parseSegment()
|
||||
{
|
||||
return new Matroska::Segment(sizeLength, dataSize, offset + idSize(id));
|
||||
}
|
||||
|
||||
@ -30,10 +30,13 @@ namespace TagLib {
|
||||
namespace Matroska {
|
||||
class Tag;
|
||||
class Attachments;
|
||||
class SeekHead;
|
||||
class Segment;
|
||||
}
|
||||
namespace EBML {
|
||||
class MkTags;
|
||||
class MkAttachments;
|
||||
class MkSeekHead;
|
||||
class MkSegment : public MasterElement
|
||||
{
|
||||
public:
|
||||
@ -44,10 +47,14 @@ namespace TagLib {
|
||||
bool read(File &file) override;
|
||||
Matroska::Tag* parseTag();
|
||||
Matroska::Attachments* parseAttachments();
|
||||
Matroska::SeekHead* parseSeekHead();
|
||||
Matroska::Segment* parseSegment();
|
||||
|
||||
private:
|
||||
offset_t dataOffset = 0;
|
||||
MkTags *tags = nullptr;
|
||||
MkAttachments *attachments = nullptr;
|
||||
MkSeekHead *seekHead = nullptr;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ Matroska::Tag* EBML::MkTags::parse()
|
||||
auto mTag = new Matroska::Tag();
|
||||
mTag->setOffset(offset);
|
||||
mTag->setSize(getSize());
|
||||
mTag->setID(id);
|
||||
|
||||
// Loop through each <Tag> element
|
||||
for(auto tagsChild : elements) {
|
||||
|
||||
@ -41,7 +41,7 @@ namespace TagLib {
|
||||
MkTags()
|
||||
: MasterElement(ElementIDs::MkTags, 0, 0, 0)
|
||||
{}
|
||||
//virtual void read(File &file) override;
|
||||
|
||||
Matroska::Tag* parse();
|
||||
|
||||
};
|
||||
|
||||
@ -58,10 +58,8 @@ ByteVector EBML::UIntElement::render()
|
||||
dataSize = 8;
|
||||
|
||||
ByteVector buffer = renderId();
|
||||
//dataSize = minSize(value);
|
||||
buffer.append(renderVINT(dataSize, 0));
|
||||
unsigned long long value = this->value;
|
||||
//debug(Utils::formatString("Writing %llu", value));
|
||||
|
||||
static const auto byteOrder = Utils::systemByteOrder();
|
||||
if(byteOrder == Utils::LittleEndian)
|
||||
|
||||
60
taglib/matroska/ebml/ebmlvoidelement.cpp
Normal file
60
taglib/matroska/ebml/ebmlvoidelement.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "ebmlvoidelement.h"
|
||||
#include "ebmlutils.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tdebug.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
ByteVector EBML::VoidElement::render()
|
||||
{
|
||||
offset_t bytesNeeded = targetSize;
|
||||
ByteVector buffer = renderId();
|
||||
bytesNeeded -= buffer.size();
|
||||
sizeLength = std::min(bytesNeeded, static_cast<offset_t>(8));
|
||||
bytesNeeded -= sizeLength;
|
||||
dataSize = bytesNeeded;
|
||||
buffer.append(renderVINT(dataSize, sizeLength));
|
||||
if (dataSize)
|
||||
buffer.append(ByteVector(dataSize, 0));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
offset_t EBML::VoidElement::getTargetSize() const
|
||||
{
|
||||
return targetSize;
|
||||
}
|
||||
|
||||
void EBML::VoidElement::setTargetSize(offset_t targetSize)
|
||||
{
|
||||
this->targetSize = std::max(targetSize, MIN_VOID_ELEMENT_SIZE);
|
||||
}
|
||||
|
||||
ByteVector EBML::VoidElement::renderSize(offset_t targetSize)
|
||||
{
|
||||
VoidElement element;
|
||||
element.setTargetSize(targetSize);
|
||||
return element.render();
|
||||
}
|
||||
56
taglib/matroska/ebml/ebmlvoidelement.h
Normal file
56
taglib/matroska/ebml/ebmlvoidelement.h
Normal file
@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_EBMLVOIDELEMENT_H
|
||||
#define TAGLIB_EBMLVOIDELEMENT_H
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
#include <cstdint>
|
||||
#include "ebmlelement.h"
|
||||
#include "tutils.h"
|
||||
|
||||
namespace TagLib {
|
||||
class File;
|
||||
|
||||
namespace EBML {
|
||||
inline constexpr offset_t MIN_VOID_ELEMENT_SIZE = 2;
|
||||
class VoidElement : public Element
|
||||
{
|
||||
public:
|
||||
VoidElement(int sizeLength, offset_t dataSize)
|
||||
: Element(ElementIDs::VoidElement, sizeLength, dataSize)
|
||||
{}
|
||||
VoidElement()
|
||||
: Element(ElementIDs::VoidElement, 0, 0)
|
||||
{}
|
||||
ByteVector render() override;
|
||||
offset_t getTargetSize() const;
|
||||
void setTargetSize(offset_t targetSize);
|
||||
static ByteVector renderSize(offset_t size);
|
||||
|
||||
private:
|
||||
offset_t targetSize = MIN_VOID_ELEMENT_SIZE;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@ -19,11 +19,11 @@ public:
|
||||
AttachmentsPrivate(const AttachmentsPrivate &) = delete;
|
||||
AttachmentsPrivate &operator=(const AttachmentsPrivate &) = delete;
|
||||
List<AttachedFile*> files;
|
||||
|
||||
};
|
||||
|
||||
Matroska::Attachments::Attachments()
|
||||
: d(std::make_unique<AttachmentsPrivate>())
|
||||
: Element(ElementIDs::MkAttachments),
|
||||
d(std::make_unique<AttachmentsPrivate>())
|
||||
{
|
||||
d->files.setAutoDelete(true);
|
||||
}
|
||||
@ -53,7 +53,7 @@ const Matroska::Attachments::AttachedFileList& Matroska::Attachments::attachedFi
|
||||
return d->files;
|
||||
}
|
||||
|
||||
ByteVector Matroska::Attachments::render()
|
||||
bool Matroska::Attachments::render()
|
||||
{
|
||||
EBML::MkAttachments attachments;
|
||||
for(const auto attachedFile : d->files) {
|
||||
@ -93,5 +93,14 @@ ByteVector Matroska::Attachments::render()
|
||||
attachments.appendElement(attachedFileElement);
|
||||
}
|
||||
|
||||
return attachments.render();
|
||||
auto beforeSize = size();
|
||||
auto data = attachments.render();
|
||||
auto afterSize = data.size();
|
||||
if (beforeSize != afterSize) {
|
||||
if (!emitSizeChanged(afterSize - beforeSize))
|
||||
return false;
|
||||
}
|
||||
setData(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -28,13 +28,17 @@
|
||||
|
||||
|
||||
namespace TagLib {
|
||||
class File;
|
||||
namespace EBML {
|
||||
class MkAttachments;
|
||||
}
|
||||
namespace Matroska {
|
||||
class AttachedFile;
|
||||
class File;
|
||||
class TAGLIB_EXPORT Attachments : private Element
|
||||
class TAGLIB_EXPORT Attachments
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
: private Element
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
using AttachedFileList = List<AttachedFile*>;
|
||||
@ -45,7 +49,7 @@ namespace TagLib {
|
||||
void removeAttachedFile(AttachedFile *file);
|
||||
void clear();
|
||||
const AttachedFileList& attachedFileList() const;
|
||||
ByteVector render() override;
|
||||
bool render() override;
|
||||
|
||||
private:
|
||||
friend class EBML::MkAttachments;
|
||||
|
||||
@ -1,6 +1,26 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
#include <memory>
|
||||
#include "matroskaelement.h"
|
||||
#include "tlist.h"
|
||||
#include "tfile.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
using namespace TagLib;
|
||||
@ -14,12 +34,17 @@ public:
|
||||
ElementPrivate &operator=(const ElementPrivate &) = delete;
|
||||
offset_t size = 0;
|
||||
offset_t offset = 0;
|
||||
ID id = 0;
|
||||
ByteVector data;
|
||||
List<Element*> sizeListeners;
|
||||
List<Element*> offsetListeners;
|
||||
|
||||
};
|
||||
|
||||
Matroska::Element::Element()
|
||||
Matroska::Element::Element(ID id)
|
||||
: e(std::make_unique<ElementPrivate>())
|
||||
{
|
||||
e->id = id;
|
||||
}
|
||||
Matroska::Element::~Element() = default;
|
||||
|
||||
@ -33,12 +58,97 @@ offset_t Matroska::Element::offset() const
|
||||
return e->offset;
|
||||
}
|
||||
|
||||
void Matroska::Element::setData(const ByteVector &data)
|
||||
{
|
||||
e->data = data;
|
||||
}
|
||||
|
||||
const ByteVector& Matroska::Element::data() const
|
||||
{
|
||||
return e->data;
|
||||
}
|
||||
|
||||
|
||||
void Matroska::Element::setOffset(offset_t offset)
|
||||
{
|
||||
e->offset = offset;
|
||||
}
|
||||
|
||||
void Matroska::Element::adjustOffset(offset_t delta)
|
||||
{
|
||||
e->offset += delta;
|
||||
}
|
||||
|
||||
void Matroska::Element::setSize(offset_t size)
|
||||
{
|
||||
e->size = size;
|
||||
}
|
||||
}
|
||||
|
||||
Matroska::Element::ID Matroska::Element::id() const
|
||||
{
|
||||
return e->id;
|
||||
}
|
||||
|
||||
void Matroska::Element::addSizeListener(Element *element)
|
||||
{
|
||||
e->sizeListeners.append(element);
|
||||
}
|
||||
|
||||
void Matroska::Element::addSizeListeners(const List<Element*> &elements)
|
||||
{
|
||||
e->sizeListeners.append(elements);
|
||||
}
|
||||
|
||||
void Matroska::Element::addOffsetListener(Element *element)
|
||||
{
|
||||
e->offsetListeners.append(element);
|
||||
}
|
||||
|
||||
void Matroska::Element::addOffsetListeners(const List<Element*> &elements)
|
||||
{
|
||||
e->offsetListeners.append(elements);
|
||||
}
|
||||
|
||||
void Matroska::Element::setID(ID id)
|
||||
{
|
||||
e->id = id;
|
||||
}
|
||||
|
||||
bool Matroska::Element::emitSizeChanged(offset_t delta)
|
||||
{
|
||||
for(auto element : e->sizeListeners) {
|
||||
if (!element->sizeChanged(*this, delta))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matroska::Element::emitOffsetChanged(offset_t delta)
|
||||
{
|
||||
for(auto element : e->offsetListeners) {
|
||||
if(!element->offsetChanged(*this, delta))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matroska::Element::sizeChanged(Element &caller, offset_t delta)
|
||||
{
|
||||
if (caller.offset() < e->offset) {
|
||||
e->offset += delta;
|
||||
//return emitOffsetChanged(delta);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matroska::Element::offsetChanged(Element &caller, offset_t delta)
|
||||
{
|
||||
// Most elements don't need to handle this
|
||||
return true;
|
||||
}
|
||||
|
||||
void Matroska::Element::write(TagLib::File &file)
|
||||
{
|
||||
file.insert(e->data, e->offset, e->size);
|
||||
e->size = e->data.size();
|
||||
}
|
||||
|
||||
@ -20,32 +20,60 @@
|
||||
|
||||
#ifndef HAS_MATROSKAELEMENT_H
|
||||
#define HAS_MATROSKAELEMENT_H
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
#include <memory>
|
||||
#include "taglib_export.h"
|
||||
#include "tutils.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tlist.h"
|
||||
|
||||
|
||||
namespace TagLib {
|
||||
class File;
|
||||
namespace Matroska {
|
||||
class TAGLIB_EXPORT Element
|
||||
{
|
||||
public:
|
||||
Element();
|
||||
using ID = unsigned int;
|
||||
Element(ID id);
|
||||
virtual ~Element();
|
||||
virtual ByteVector render() = 0;
|
||||
|
||||
offset_t size() const;
|
||||
offset_t offset() const;
|
||||
ID id() const;
|
||||
void setOffset(offset_t offset);
|
||||
void adjustOffset(offset_t delta);
|
||||
void setSize(offset_t size);
|
||||
void setID(ID id);
|
||||
//virtual ByteVector render() = 0;
|
||||
virtual bool render() = 0;
|
||||
void setData(const ByteVector &data);
|
||||
const ByteVector& data() const;
|
||||
virtual void write(TagLib::File &file);
|
||||
void addSizeListener(Element *element);
|
||||
void addSizeListeners(const List<Element*> &elements);
|
||||
void addOffsetListener(Element *element);
|
||||
void addOffsetListeners(const List<Element*> &elements);
|
||||
//virtual void updatePosition(Element &caller, offset_t delta) = 0;
|
||||
bool emitSizeChanged(offset_t delta);
|
||||
bool emitOffsetChanged(offset_t delta);
|
||||
virtual bool offsetChanged(Element &caller, offset_t delta);
|
||||
virtual bool sizeChanged(Element &caller, offset_t delta);
|
||||
|
||||
private:
|
||||
class ElementPrivate;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
@ -21,6 +21,8 @@
|
||||
#include "matroskafile.h"
|
||||
#include "matroskatag.h"
|
||||
#include "matroskaattachments.h"
|
||||
#include "matroskaseekhead.h"
|
||||
#include "matroskasegment.h"
|
||||
#include "ebmlutils.h"
|
||||
#include "ebmlelement.h"
|
||||
#include "ebmlmksegment.h"
|
||||
@ -42,16 +44,15 @@ public:
|
||||
{
|
||||
delete tag;
|
||||
delete attachments;
|
||||
delete seekHead;
|
||||
}
|
||||
|
||||
FilePrivate(const FilePrivate &) = delete;
|
||||
FilePrivate &operator=(const FilePrivate &) = delete;
|
||||
Matroska::Tag *tag = nullptr;
|
||||
Matroska::Attachments *attachments = nullptr;
|
||||
offset_t segmentSizeOffset = 0;
|
||||
offset_t segmentSizeLength = 0;
|
||||
offset_t segmentDataSize = 0;
|
||||
|
||||
Attachments *attachments = nullptr;
|
||||
SeekHead *seekHead = nullptr;
|
||||
Segment *segment = nullptr;
|
||||
};
|
||||
|
||||
Matroska::File::File(FileName file, bool readProperties)
|
||||
@ -65,6 +66,7 @@ Matroska::File::File(FileName file, bool readProperties)
|
||||
}
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
Matroska::File::File(IOStream *stream, bool readProperties)
|
||||
: TagLib::File(stream),
|
||||
d(std::make_unique<FilePrivate>())
|
||||
@ -76,6 +78,7 @@ Matroska::File::File(IOStream *stream, bool readProperties)
|
||||
}
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
Matroska::File::~File() = default;
|
||||
|
||||
TagLib::Tag* Matroska::File::tag() const
|
||||
@ -129,9 +132,6 @@ void Matroska::File::read(bool readProperties)
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
d->segmentSizeLength = segment->getSizeLength();
|
||||
d->segmentSizeOffset = tell() - d->segmentSizeLength;
|
||||
d->segmentDataSize = segment->getDataSize();
|
||||
|
||||
// Read the segment into memory from file
|
||||
if(!segment->read(*this)) {
|
||||
@ -139,11 +139,11 @@ void Matroska::File::read(bool readProperties)
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the tag
|
||||
|
||||
// Parse the elements
|
||||
d->segment = segment->parseSegment();
|
||||
d->seekHead = segment->parseSeekHead();
|
||||
d->tag = segment->parseTag();
|
||||
|
||||
// Parse the attachments
|
||||
d->attachments = segment->parseAttachments();
|
||||
|
||||
setValid(true);
|
||||
@ -151,86 +151,82 @@ void Matroska::File::read(bool readProperties)
|
||||
|
||||
bool Matroska::File::save()
|
||||
{
|
||||
std::vector<Element*> renderListExisting;
|
||||
std::vector<Element*> renderListNew;
|
||||
offset_t newSegmentDataSize = d->segmentDataSize;
|
||||
|
||||
|
||||
if(d->tag) {
|
||||
if(d->tag->size())
|
||||
renderListExisting.push_back(d->tag);
|
||||
else
|
||||
renderListNew.push_back(d->tag);
|
||||
if(readOnly()) {
|
||||
debug("Matroska::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
if(!isValid()) {
|
||||
debug("Matroska::File::save() -- File is not valid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(d->attachments) {
|
||||
//d->attachments->setOffset(d->tag->offset());
|
||||
//renderListExisting.push_back(d->attachments);
|
||||
if(d->attachments->size())
|
||||
renderListExisting.push_back(d->attachments);
|
||||
else
|
||||
renderListNew.push_back(d->attachments);
|
||||
List<Element*> renderList;
|
||||
List<Element*> newElements;
|
||||
|
||||
|
||||
}
|
||||
// List of all possible elements we can write
|
||||
List<Element*> elements {
|
||||
d->attachments,
|
||||
d->tag
|
||||
};
|
||||
|
||||
|
||||
// Render from end to beginning so we don't have to shift
|
||||
// the file offsets
|
||||
std::sort(renderListExisting.begin(),
|
||||
renderListExisting.end(),
|
||||
[](auto a, auto b) { return a->offset() > b->offset(); }
|
||||
);
|
||||
|
||||
// Overwrite existing elements
|
||||
for(auto element : renderListExisting) {
|
||||
offset_t offset = element->offset();
|
||||
offset_t originalSize = element->size();
|
||||
ByteVector data = element->render();
|
||||
insert(data, offset, originalSize);
|
||||
newSegmentDataSize += (data.size() - originalSize);
|
||||
}
|
||||
|
||||
// Add new elements to the end of file
|
||||
for(auto element : renderListNew) {
|
||||
offset_t offset = length();
|
||||
ByteVector data = element->render();
|
||||
insert(data, offset, 0);
|
||||
newSegmentDataSize += data.size();
|
||||
}
|
||||
|
||||
// Write the new segment data size
|
||||
if(newSegmentDataSize != d->segmentDataSize) {
|
||||
auto segmentDataSizeBuffer = EBML::renderVINT(newSegmentDataSize, d->segmentSizeLength);
|
||||
insert(segmentDataSizeBuffer, d->segmentSizeOffset, d->segmentSizeLength);
|
||||
d->segmentDataSize = newSegmentDataSize;
|
||||
}
|
||||
|
||||
/*
|
||||
auto&& renderElements [&d->segmentDataSize](Element *element) {
|
||||
auto offset = element->offset();
|
||||
if(!offset)
|
||||
}
|
||||
|
||||
if(d->tag) {
|
||||
ByteVector tag = d->tag->render();
|
||||
auto tagsOriginalSize = d->tag->size();
|
||||
auto tagsOffset = d->tag->offset();
|
||||
|
||||
if(!tagsOriginalSize) {
|
||||
tagsOffset = d->segmentSizeOffset + d->segmentSizeLength + d->segmentDataSize;
|
||||
/* Build render list. New elements will be added
|
||||
* to the end of the file. For new elements,
|
||||
* the order is from least likely to change,
|
||||
* to most likely to change:
|
||||
* 1. Bookmarks (todo)
|
||||
* 2. Attachments
|
||||
* 3. Tags
|
||||
*/
|
||||
for (auto element : elements) {
|
||||
if (!element)
|
||||
continue;
|
||||
if (element->size())
|
||||
renderList.append(element);
|
||||
else {
|
||||
element->setOffset(length());
|
||||
newElements.append(element);
|
||||
}
|
||||
insert(tag, tagsOffset, tagsOriginalSize);
|
||||
d->segmentDataSize += (tag.size() - tagsOriginalSize);
|
||||
auto segmentDataSizeBuffer = EBML::renderVINT(d->segmentDataSize, d->segmentSizeLength);
|
||||
insert(segmentDataSizeBuffer, d->segmentSizeOffset, d->segmentSizeLength);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if(d->attachments) {
|
||||
ByteVector attachments = d->attachments->render();
|
||||
if (renderList.isEmpty())
|
||||
return true;
|
||||
|
||||
auto sortAscending = [](const auto a, const auto b) { return a->offset() < b->offset(); };
|
||||
renderList.sort(sortAscending);
|
||||
renderList.append(newElements);
|
||||
|
||||
// Add our new elements to the Seek Head (if the file has one)
|
||||
if (d->seekHead) {
|
||||
auto segmentDataOffset = d->segment->dataOffset();
|
||||
for (auto element : newElements)
|
||||
d->seekHead->addEntry(element->id(), element->offset() - segmentDataOffset);
|
||||
d->seekHead->sort();
|
||||
}
|
||||
*/
|
||||
|
||||
// Set up listeners, add seek head and segment length to the end
|
||||
for(auto it = renderList.begin(); it != renderList.end(); ++it) {
|
||||
for (auto it2 = std::next(it); it2 != renderList.end(); ++it2)
|
||||
(*it)->addSizeListener(*it2);
|
||||
if (d->seekHead)
|
||||
(*it)->addSizeListener(d->seekHead);
|
||||
(*it)->addSizeListener(d->segment);
|
||||
}
|
||||
if(d->seekHead) {
|
||||
d->seekHead->addSizeListeners(renderList);
|
||||
renderList.append(d->seekHead);
|
||||
}
|
||||
d->segment->addSizeListeners(renderList);
|
||||
renderList.append(d->segment);
|
||||
|
||||
// Render the elements
|
||||
for(auto element : renderList) {
|
||||
if (!element->render())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write out to file
|
||||
renderList.sort(sortAscending);
|
||||
for(auto element : renderList)
|
||||
element->write(*this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
|
||||
121
taglib/matroska/matroskaseekhead.cpp
Normal file
121
taglib/matroska/matroskaseekhead.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "matroskaseekhead.h"
|
||||
#include "ebmlmkseekhead.h"
|
||||
#include "ebmlbinaryelement.h"
|
||||
#include "ebmluintelement.h"
|
||||
#include "ebmlmasterelement.h"
|
||||
|
||||
#include "tdebug.h"
|
||||
#include "tfile.h"
|
||||
#include "tutils.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
void Matroska::SeekHead::addEntry(Element &element)
|
||||
{
|
||||
entries.append({element.id(), element.offset()});
|
||||
debug("adding to seekhead");
|
||||
needsRender = true;
|
||||
}
|
||||
|
||||
void Matroska::SeekHead::addEntry(ID id, offset_t offset)
|
||||
{
|
||||
entries.append({id, offset});
|
||||
needsRender = true;
|
||||
}
|
||||
|
||||
ByteVector Matroska::SeekHead::renderInternal()
|
||||
{
|
||||
auto beforeSize = size();
|
||||
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);
|
||||
idElement->setValue(ByteVector::fromUInt(id, true));
|
||||
seekElement->appendElement(idElement);
|
||||
|
||||
auto positionElement = new EBML::UIntElement(EBML::ElementIDs::MkSeekPosition);
|
||||
positionElement->setValue(static_cast<unsigned long long>(position));
|
||||
seekElement->appendElement(positionElement);
|
||||
|
||||
seekHead.appendElement(seekElement);
|
||||
}
|
||||
return seekHead.render();
|
||||
}
|
||||
|
||||
bool Matroska::SeekHead::render()
|
||||
{
|
||||
if (!needsRender)
|
||||
return true;
|
||||
|
||||
auto beforeSize = size();
|
||||
auto data = renderInternal();
|
||||
needsRender = false;
|
||||
auto afterSize = data.size();
|
||||
if (afterSize != beforeSize) {
|
||||
return false;
|
||||
// To do, handle expansion of seek head
|
||||
if (!emitSizeChanged(afterSize - beforeSize))
|
||||
return false;
|
||||
}
|
||||
|
||||
setData(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Matroska::SeekHead::write(TagLib::File &file)
|
||||
{
|
||||
if (!data().isEmpty())
|
||||
Element::write(file);
|
||||
}
|
||||
|
||||
void Matroska::SeekHead::sort()
|
||||
{
|
||||
entries.sort([](const auto &a, const auto &b) { return a.second < b.second; });
|
||||
}
|
||||
|
||||
bool Matroska::SeekHead::sizeChanged(Element &caller, offset_t delta)
|
||||
{
|
||||
ID callerID = caller.id();
|
||||
if (callerID == ElementIDs::MkSegment) {
|
||||
adjustOffset(delta);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
offset_t offset = caller.offset();
|
||||
auto it = entries.begin();
|
||||
while (it != entries.end()) {
|
||||
it = std::find_if(it,
|
||||
entries.end(),
|
||||
[offset](const auto a){ return a.second > offset; }
|
||||
);
|
||||
if (it != entries.end()) {
|
||||
it->second += delta;
|
||||
needsRender = true;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
55
taglib/matroska/matroskaseekhead.h
Normal file
55
taglib/matroska/matroskaseekhead.h
Normal file
@ -0,0 +1,55 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MATROSKASEEKHEAD_H
|
||||
#define TAGLIB_MATROSKASEEKHEAD_H
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
#include "matroskaelement.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tutils.h"
|
||||
#include "tlist.h"
|
||||
|
||||
namespace TagLib {
|
||||
class File;
|
||||
namespace Matroska {
|
||||
class SeekHead : public Element
|
||||
{
|
||||
public:
|
||||
SeekHead() : Element(ElementIDs::MkSeekHead) {};
|
||||
virtual ~SeekHead() {};
|
||||
void addEntry(Element &element);
|
||||
void addEntry(ID id, offset_t offset);
|
||||
bool render() override;
|
||||
void write(TagLib::File &file) override;
|
||||
void sort();
|
||||
//bool offsetChanged(Element &caller, offset_t delta) override;
|
||||
bool sizeChanged(Element &caller, offset_t delta) override;
|
||||
|
||||
private:
|
||||
ByteVector renderInternal();
|
||||
List<std::pair<unsigned int, offset_t>> entries;
|
||||
bool needsRender = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
45
taglib/matroska/matroskasegment.cpp
Normal file
45
taglib/matroska/matroskasegment.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "matroskasegment.h"
|
||||
#include "ebmlutils.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
bool Matroska::Segment::render()
|
||||
{
|
||||
auto data = EBML::renderVINT(dataSize, sizeLength);
|
||||
if (data.size() != sizeLength) {
|
||||
sizeLength = 8;
|
||||
if (!emitSizeChanged(sizeLength - data.size()))
|
||||
return false;
|
||||
data = EBML::renderVINT(dataSize, sizeLength);
|
||||
if (data.size() != sizeLength)
|
||||
return false;
|
||||
}
|
||||
setData(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matroska::Segment::sizeChanged(Element &caller, offset_t delta)
|
||||
{
|
||||
dataSize += delta;
|
||||
return true;
|
||||
}
|
||||
52
taglib/matroska/matroskasegment.h
Normal file
52
taglib/matroska/matroskasegment.h
Normal file
@ -0,0 +1,52 @@
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MATROSKASEGMENT_H
|
||||
#define TAGLIB_MATROSKASEGMENT_H
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
#include "matroskaelement.h"
|
||||
#include "tutils.h"
|
||||
|
||||
namespace TagLib {
|
||||
namespace 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);
|
||||
}
|
||||
virtual ~Segment() = default;
|
||||
bool render() override;
|
||||
bool sizeChanged(Element &caller, offset_t delta) override;
|
||||
offset_t dataOffset() const { return offset() + sizeLength; }
|
||||
|
||||
private:
|
||||
offset_t sizeLength;
|
||||
offset_t dataSize;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@ -50,11 +50,13 @@ class Matroska::Tag::TagPrivate
|
||||
TagPrivate() = default;
|
||||
~TagPrivate() = default;
|
||||
List<SimpleTag*> tags;
|
||||
ByteVector data;
|
||||
|
||||
};
|
||||
|
||||
Matroska::Tag::Tag()
|
||||
: TagLib::Tag(),
|
||||
Element(ElementIDs::MkTags),
|
||||
d(std::make_unique<TagPrivate>())
|
||||
{
|
||||
d->tags.setAutoDelete(true);
|
||||
@ -183,7 +185,7 @@ bool Matroska::Tag::isEmpty() const
|
||||
return d->tags.isEmpty();
|
||||
}
|
||||
|
||||
ByteVector Matroska::Tag::render()
|
||||
bool Matroska::Tag::render()
|
||||
{
|
||||
EBML::MkTags tags;
|
||||
List<List<SimpleTag*>*> targetList;
|
||||
@ -256,7 +258,15 @@ ByteVector Matroska::Tag::render()
|
||||
tags.appendElement(tag);
|
||||
}
|
||||
|
||||
return tags.render();
|
||||
auto data = tags.render();
|
||||
auto beforeSize = size();
|
||||
auto afterSize = data.size();
|
||||
if (afterSize != beforeSize) {
|
||||
if (!emitSizeChanged(afterSize - beforeSize))
|
||||
return false;
|
||||
}
|
||||
setData(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
|
||||
@ -33,13 +33,17 @@
|
||||
#include "matroskasimpletag.h"
|
||||
|
||||
namespace TagLib {
|
||||
class File;
|
||||
namespace EBML {
|
||||
class MkTags;
|
||||
}
|
||||
|
||||
namespace Matroska {
|
||||
using SimpleTagsList = List<SimpleTag*>;
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag, private Element
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
, private Element
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
Tag();
|
||||
@ -63,7 +67,7 @@ namespace TagLib {
|
||||
void setYear(unsigned int i) override;
|
||||
void setTrack(unsigned int i) override;
|
||||
bool isEmpty() const override;
|
||||
ByteVector render() override;
|
||||
bool render() override;
|
||||
PropertyMap properties() const override;
|
||||
PropertyMap setProperties(const PropertyMap &propertyMap) override;
|
||||
template <typename T>
|
||||
|
||||
Reference in New Issue
Block a user