4 #include <c++utilities/conversion/binaryconversion.h>
38 std::uint64_t MatroskaCuePositionUpdater::totalSize()
const
41 std::uint64_t size = m_sizes.at(m_cuesElement);
42 return 4 + EbmlElement::calculateSizeDenotationLength(size) + size;
54 static const string context(
"parsing \"Cues\"-element");
56 std::uint64_t cuesElementSize = 0, cuePointElementSize, cueTrackPositionsElementSize, cueReferenceElementSize, pos, relPos, statePos;
57 EbmlElement *cueRelativePositionElement, *cueClusterPositionElement;
60 cuePointElement->
parse(diag);
61 switch (cuePointElement->id()) {
66 cuePointElementSize = 0;
69 cuePointChild->parse(diag);
70 switch (cuePointChild->id()) {
75 cuePointChild->makeBuffer();
76 cuePointElementSize += cuePointChild->totalSize();
79 cueTrackPositionsElementSize = 0;
80 cueRelativePositionElement = cueClusterPositionElement =
nullptr;
82 cueTrackPositionsChild = cueTrackPositionsChild->
nextSibling()) {
84 cueTrackPositionsChild->
parse(diag);
85 switch (cueTrackPositionsChild->id()) {
89 cueTrackPositionsChild->makeBuffer();
90 cueTrackPositionsElementSize += cueTrackPositionsChild->totalSize();
93 relPos = (cueRelativePositionElement = cueTrackPositionsChild)->readUInteger();
96 pos = (cueClusterPositionElement = cueTrackPositionsChild)->readUInteger();
97 cueTrackPositionsElementSize += 2u + EbmlElement::calculateUIntegerLength(pos);
98 m_offsets.emplace(cueTrackPositionsChild, pos);
99 m_cueElementByOriginalOffset.emplace(pos, cueTrackPositionsChild);
102 statePos = cueTrackPositionsChild->readUInteger();
103 cueTrackPositionsElementSize += 2u + EbmlElement::calculateUIntegerLength(statePos);
104 m_offsets.emplace(cueTrackPositionsChild, statePos);
105 m_cueElementByOriginalOffset.emplace(statePos, cueTrackPositionsChild);
108 cueReferenceElementSize = 0;
110 cueReferenceChild = cueReferenceChild->
nextSibling()) {
112 cueReferenceChild->parse(diag);
113 switch (cueReferenceChild->id()) {
119 cueReferenceChild->makeBuffer();
120 cueReferenceElementSize += cueReferenceChild->totalSize();
124 statePos = cueReferenceChild->readUInteger();
125 cueReferenceElementSize += 2u + EbmlElement::calculateUIntegerLength(statePos);
126 m_offsets.emplace(cueReferenceChild, statePos);
127 m_cueElementByOriginalOffset.emplace(statePos, cueReferenceChild);
130 diag.emplace_back(DiagLevel::Warning,
131 "\"CueReference\"-element contains a element which is not known to the parser. It will be ignored.", context);
134 cueTrackPositionsElementSize
135 += 1 + EbmlElement::calculateSizeDenotationLength(cueReferenceElementSize) + cueReferenceElementSize;
136 m_sizes.emplace(cueTrackPositionsChild, cueReferenceElementSize);
139 diag.emplace_back(DiagLevel::Warning,
140 "\"CueTrackPositions\"-element contains a element which is not known to the parser. It will be ignored.", context);
143 if (!cueClusterPositionElement) {
145 DiagLevel::Critical,
"\"CueTrackPositions\"-element does not contain mandatory \"CueClusterPosition\"-element.", context);
146 }
else if (cueRelativePositionElement) {
147 cueTrackPositionsElementSize += 2u + EbmlElement::calculateUIntegerLength(relPos);
148 m_relativeOffsets.emplace(piecewise_construct, forward_as_tuple(cueRelativePositionElement), forward_as_tuple(pos, relPos));
149 m_cueRelativePositionElementByOriginalOffsets.emplace(
150 piecewise_construct, forward_as_tuple(pos, relPos), forward_as_tuple(cueRelativePositionElement));
153 += 1 + EbmlElement::calculateSizeDenotationLength(cueTrackPositionsElementSize) + cueTrackPositionsElementSize;
154 m_sizes.emplace(cuePointChild, cueTrackPositionsElementSize);
157 diag.emplace_back(DiagLevel::Warning,
158 "\"CuePoint\"-element contains a element which is not a \"CueTime\"- or a \"CueTrackPositions\"-element. It will be ignored.",
162 cuesElementSize += 1 + EbmlElement::calculateSizeDenotationLength(cuePointElementSize) + cuePointElementSize;
163 m_sizes.emplace(cuePointElement, cuePointElementSize);
167 DiagLevel::Warning,
"\"Cues\"-element contains a element which is not a \"CuePoint\"-element. It will be ignored.", context);
170 m_sizes.emplace(m_cuesElement = cuesElement, cuesElementSize);
177 bool MatroskaCuePositionUpdater::updateOffsets(std::uint64_t originalOffset, std::uint64_t newOffset)
179 auto updated =
false;
180 const auto newOffsetLength =
static_cast<int>(EbmlElement::calculateUIntegerLength(newOffset));
181 for (
auto cueElementRange = m_cueElementByOriginalOffset.equal_range(originalOffset); cueElementRange.first != cueElementRange.second;
182 ++cueElementRange.first) {
183 auto *
const cueElement = cueElementRange.first->second;
184 const auto offsetIterator = m_offsets.find(cueElement);
185 if (offsetIterator == m_offsets.end()) {
188 auto &offset = offsetIterator->second;
189 if (offset.currentValue() != newOffset) {
191 = updateSize(cueElement->parent(), newOffsetLength -
static_cast<int>(EbmlElement::calculateUIntegerLength(offset.currentValue())))
193 offset.update(newOffset);
203 bool MatroskaCuePositionUpdater::updateRelativeOffsets(
204 std::uint64_t referenceOffset, std::uint64_t originalRelativeOffset, std::uint64_t newRelativeOffset)
206 auto updated =
false;
207 const auto newRelativeOffsetLength =
static_cast<int>(EbmlElement::calculateUIntegerLength(newRelativeOffset));
208 for (
auto cueElementRange = m_cueRelativePositionElementByOriginalOffsets.equal_range(std::make_pair(referenceOffset, originalRelativeOffset));
209 cueElementRange.first != cueElementRange.second; ++cueElementRange.first) {
210 auto *
const cueRelativePositionElement = cueElementRange.first->second;
211 const auto offsetIterator = m_relativeOffsets.find(cueRelativePositionElement);
212 if (offsetIterator == m_relativeOffsets.end()) {
215 auto &offset = offsetIterator->second;
216 if (offset.currentValue() != newRelativeOffset) {
217 updated = updateSize(cueRelativePositionElement->parent(),
218 newRelativeOffsetLength -
static_cast<int>(EbmlElement::calculateUIntegerLength(offset.currentValue())))
220 offset.update(newRelativeOffset);
230 bool MatroskaCuePositionUpdater::updateSize(
EbmlElement *element,
int shift)
241 const auto sizeIterator = m_sizes.find(element);
242 if (sizeIterator == m_sizes.end()) {
245 std::uint64_t &size = sizeIterator->second;
247 const std::uint64_t newSize = shift > 0 ? size +
static_cast<std::uint64_t
>(shift) : size -
static_cast<std::uint64_t
>(-shift);
249 const bool updated = updateSize(element->
parent(),
250 shift +
static_cast<int>(EbmlElement::calculateSizeDenotationLength(newSize))
251 -
static_cast<int>(EbmlElement::calculateSizeDenotationLength(size)));
260 void MatroskaCuePositionUpdater::make(ostream &stream,
Diagnostics &diag)
262 static const string context(
"making \"Cues\"-element");
263 if (!m_cuesElement) {
264 diag.emplace_back(DiagLevel::Warning,
"No cues written; the cues of the source file could not be parsed correctly.", context);
273 stream.write(buff, 4);
274 len = EbmlElement::makeSizeDenotation(m_sizes[m_cuesElement], buff);
275 stream.write(buff, len);
278 cuePointElement->parse(diag);
279 switch (cuePointElement->id()) {
286 len = EbmlElement::makeSizeDenotation(m_sizes[cuePointElement], buff);
287 stream.write(buff, len);
289 cuePointChild->parse(diag);
290 switch (cuePointChild->id()) {
296 cuePointChild->copyBuffer(stream);
297 cuePointChild->discardBuffer();
302 len = EbmlElement::makeSizeDenotation(m_sizes[cuePointChild], buff);
303 stream.write(buff, len);
305 cueTrackPositionsChild = cueTrackPositionsChild->
nextSibling()) {
306 cueTrackPositionsChild->parse(diag);
307 switch (cueTrackPositionsChild->id()) {
312 cueTrackPositionsChild->copyBuffer(stream);
313 cueTrackPositionsChild->discardBuffer();
316 if (
const auto relativeOffset = m_relativeOffsets.find(cueTrackPositionsChild);
317 relativeOffset != m_relativeOffsets.end()) {
318 EbmlElement::makeSimpleElement(stream, cueTrackPositionsChild->id(), relativeOffset->second.currentValue());
326 EbmlElement::makeSimpleElement(
327 stream, cueTrackPositionsChild->id(), m_offsets.at(cueTrackPositionsChild).currentValue());
332 len = EbmlElement::makeSizeDenotation(m_sizes[cueTrackPositionsChild], buff);
333 stream.write(buff, len);
335 cueReferenceChild = cueReferenceChild->
nextSibling()) {
336 cueReferenceChild->parse(diag);
337 switch (cueReferenceChild->id()) {
344 cueReferenceChild->copyBuffer(stream);
345 cueReferenceChild->discardBuffer();
346 cueReferenceChild->copyEntirely(stream, diag,
nullptr);
351 EbmlElement::makeSimpleElement(
352 stream, cueReferenceChild->id(), m_offsets.at(cueReferenceChild).currentValue());
355 diag.emplace_back(DiagLevel::Warning,
356 "\"CueReference\"-element contains a element which is not known to the parser. It will be ignored.",
362 diag.emplace_back(DiagLevel::Warning,
363 "\"CueTrackPositions\"-element contains a element which is not known to the parser. It will be ignored.",
369 diag.emplace_back(DiagLevel::Warning,
370 "\"CuePoint\"-element contains a element which is not a \"CueTime\"- or a \"CueTrackPositions\"-element. It will be "
378 DiagLevel::Warning,
"\"Cues\"-element contains a element which is not a \"CuePoint\"-element. It will be ignored.", context);
381 }
catch (
const out_of_range &) {
383 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.
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...
Contains all classes and functions of the TagInfo library.