4#include "../mediafileinfo.h"
6#include <c++utilities/conversion/binaryconversion.h>
43 std::uint64_t size = m_sizes.at(m_cuesElement);
56 static const string context(
"parsing \"Cues\"-element");
58 std::uint64_t cuesElementSize = 0, cuePointElementSize, cueTrackPositionsElementSize, cueReferenceElementSize, pos, relPos, statePos;
59 EbmlElement *cueRelativePositionElement, *cueClusterPositionElement;
62 cuePointElement->
parse(diag);
63 switch (cuePointElement->id()) {
68 cuePointElementSize = 0;
71 cuePointChild->parse(diag);
72 switch (cuePointChild->id()) {
77 cuePointChild->makeBuffer();
78 cuePointElementSize += cuePointChild->totalSize();
81 cueTrackPositionsElementSize = 0;
82 cueRelativePositionElement = cueClusterPositionElement =
nullptr;
84 cueTrackPositionsChild = cueTrackPositionsChild->
nextSibling()) {
86 cueTrackPositionsChild->
parse(diag);
87 switch (cueTrackPositionsChild->id()) {
91 cueTrackPositionsChild->makeBuffer();
92 cueTrackPositionsElementSize += cueTrackPositionsChild->totalSize();
95 relPos = (cueRelativePositionElement = cueTrackPositionsChild)->readUInteger();
98 pos = (cueClusterPositionElement = cueTrackPositionsChild)->readUInteger();
100 m_offsets.emplace(cueTrackPositionsChild, pos);
101 m_cueElementByOriginalOffset.emplace(pos, cueTrackPositionsChild);
104 statePos = cueTrackPositionsChild->readUInteger();
106 m_offsets.emplace(cueTrackPositionsChild, statePos);
107 m_cueElementByOriginalOffset.emplace(statePos, cueTrackPositionsChild);
110 cueReferenceElementSize = 0;
112 cueReferenceChild = cueReferenceChild->nextSibling()) {
114 cueReferenceChild->parse(diag);
115 switch (cueReferenceChild->id()) {
121 cueReferenceChild->makeBuffer();
122 cueReferenceElementSize += cueReferenceChild->totalSize();
126 statePos = cueReferenceChild->readUInteger();
128 m_offsets.emplace(cueReferenceChild, statePos);
129 m_cueElementByOriginalOffset.emplace(statePos, cueReferenceChild);
133 "\"CueReference\"-element contains a element which is not known to the parser. It will be ignored.", context);
136 cueTrackPositionsElementSize
138 m_sizes.emplace(cueTrackPositionsChild, cueReferenceElementSize);
142 "\"CueTrackPositions\"-element contains a element which is not known to the parser. It will be ignored.", context);
145 if (!cueClusterPositionElement) {
147 DiagLevel::Critical,
"\"CueTrackPositions\"-element does not contain mandatory \"CueClusterPosition\"-element.", context);
148 }
else if (cueRelativePositionElement) {
150 m_relativeOffsets.emplace(piecewise_construct, forward_as_tuple(cueRelativePositionElement), forward_as_tuple(pos, relPos));
151 m_cueRelativePositionElementByOriginalOffsets.emplace(
152 piecewise_construct, forward_as_tuple(pos, relPos), forward_as_tuple(cueRelativePositionElement));
156 m_sizes.emplace(cuePointChild, cueTrackPositionsElementSize);
160 "\"CuePoint\"-element contains a element which is not a \"CueTime\"- or a \"CueTrackPositions\"-element. It will be ignored.",
165 m_sizes.emplace(cuePointElement, cuePointElementSize);
169 DiagLevel::Warning,
"\"Cues\"-element contains a element which is not a \"CuePoint\"-element. It will be ignored.", context);
172 m_sizes.emplace(m_cuesElement =
cuesElement, cuesElementSize);
181 auto updated =
false;
183 for (
auto cueElementRange = m_cueElementByOriginalOffset.equal_range(originalOffset); cueElementRange.first != cueElementRange.second;
184 ++cueElementRange.first) {
185 auto *
const cueElement = cueElementRange.first->second;
186 const auto offsetIterator = m_offsets.find(cueElement);
187 if (offsetIterator == m_offsets.end()) {
190 auto &offset = offsetIterator->second;
191 if (offset.currentValue() != newOffset) {
195 offset.update(newOffset);
206 std::uint64_t referenceOffset, std::uint64_t originalRelativeOffset, std::uint64_t newRelativeOffset)
208 auto updated =
false;
210 for (
auto cueElementRange = m_cueRelativePositionElementByOriginalOffsets.equal_range(std::make_pair(referenceOffset, originalRelativeOffset));
211 cueElementRange.first != cueElementRange.second; ++cueElementRange.first) {
212 auto *
const cueRelativePositionElement = cueElementRange.first->second;
213 const auto offsetIterator = m_relativeOffsets.find(cueRelativePositionElement);
214 if (offsetIterator == m_relativeOffsets.end()) {
217 auto &offset = offsetIterator->second;
218 if (offset.currentValue() != newRelativeOffset) {
219 updated = updateSize(cueRelativePositionElement->parent(),
222 offset.update(newRelativeOffset);
232bool MatroskaCuePositionUpdater::updateSize(
EbmlElement *element,
int shift)
243 const auto sizeIterator = m_sizes.find(element);
244 if (sizeIterator == m_sizes.end()) {
247 std::uint64_t &size = sizeIterator->second;
249 const std::uint64_t newSize = shift > 0 ? size +
static_cast<std::uint64_t
>(shift) : size - static_cast<std::uint64_t>(-shift);
251 const bool updated = updateSize(element->
parent(),
264 static const string context(
"making \"Cues\"-element");
265 if (!m_cuesElement) {
266 diag.emplace_back(
DiagLevel::Warning,
"No cues written; the cues of the source file could not be parsed correctly.", context);
275 stream.write(buff, 4);
277 stream.write(buff, len);
279 for (
EbmlElement *cuePointElement = m_cuesElement->
firstChild(); cuePointElement; cuePointElement = cuePointElement->nextSibling()) {
280 cuePointElement->parse(diag);
281 switch (cuePointElement->id()) {
289 stream.write(buff, len);
290 for (
EbmlElement *cuePointChild = cuePointElement->
firstChild(); cuePointChild; cuePointChild = cuePointChild->nextSibling()) {
291 cuePointChild->parse(diag);
292 switch (cuePointChild->id()) {
298 cuePointChild->copyBuffer(stream);
299 cuePointChild->discardBuffer();
305 stream.write(buff, len);
307 cueTrackPositionsChild = cueTrackPositionsChild->nextSibling()) {
308 cueTrackPositionsChild->parse(diag);
309 switch (cueTrackPositionsChild->id()) {
314 cueTrackPositionsChild->copyBuffer(stream);
315 cueTrackPositionsChild->discardBuffer();
318 if (
const auto relativeOffset = m_relativeOffsets.find(cueTrackPositionsChild);
319 relativeOffset != m_relativeOffsets.end()) {
329 stream, cueTrackPositionsChild->id(), m_offsets.at(cueTrackPositionsChild).currentValue());
335 stream.write(buff, len);
337 cueReferenceChild = cueReferenceChild->nextSibling()) {
338 cueReferenceChild->parse(diag);
339 switch (cueReferenceChild->id()) {
346 cueReferenceChild->copyBuffer(stream);
347 cueReferenceChild->discardBuffer();
348 cueReferenceChild->copyEntirely(stream, diag,
nullptr);
354 stream, cueReferenceChild->id(), m_offsets.at(cueReferenceChild).currentValue());
358 "\"CueReference\"-element contains a element which is not known to the parser. It will be ignored.",
365 "\"CueTrackPositions\"-element contains a element which is not known to the parser. It will be ignored.",
372 "\"CuePoint\"-element contains a element which is not a \"CueTime\"- or a \"CueTrackPositions\"-element. It will be "
380 DiagLevel::Warning,
"\"Cues\"-element contains a element which is not a \"CuePoint\"-element. It will be ignored.", context);
383 }
catch (
const out_of_range &) {
385 DiagLevel::Critical,
"Unable to write the file index because the index of the original file could not be parsed correctly.", context);
The Diagnostics class is a container for DiagMessage.
The EbmlElement class helps to parse EBML files such as Matroska files.
static void makeSimpleElement(std::ostream &stream, IdentifierType id, std::uint64_t content)
Makes a simple EBML element.
static std::uint8_t calculateSizeDenotationLength(std::uint64_t size)
Returns the length of the size denotation for the specified size in byte.
static std::uint8_t makeSizeDenotation(std::uint64_t size, char *buff)
Makes the size denotation for the specified size and stores it to buff.
static std::uint8_t calculateUIntegerLength(std::uint64_t integer)
Returns the length of the specified unsigned integer in byte.
ImplementationType * nextSibling()
Returns the next sibling of the element.
ImplementationType * parent()
Returns the parent of the element.
ImplementationType * firstChild()
Returns the first child of the element.
void parse(Diagnostics &diag)
Parses the header information of the element which is read from the related stream at the start offse...
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
std::uint64_t totalSize() const
Returns how many bytes will be written when calling the make() method.
bool updateOffsets(std::uint64_t originalOffset, std::uint64_t newOffset)
Sets the offset of the entries with the specified originalOffset to newOffset.
bool updateRelativeOffsets(std::uint64_t referenceOffset, std::uint64_t originalRelativeOffset, std::uint64_t newRelativeOffset)
Sets the relative offset of the entries with the specified originalRelativeOffset and the specified r...
void clear()
Resets the object to its initial state.
void make(std::ostream &stream, Diagnostics &diag)
Writes the previously parsed "Cues"-element with updated positions to the specified stream.
void parse(EbmlElement *cuesElement, Diagnostics &diag)
Parses the specified cuesElement.
EbmlElement * cuesElement() const
Returns the "Cues"-element specified when calling the parse() method.
Contains all classes and functions of the TagInfo library.