4 #include <c++utilities/conversion/binaryconversion.h> 7 using namespace ConversionUtilities;
38 uint64 MatroskaCuePositionUpdater::totalSize()
const 41 uint64 size = m_sizes.at(m_cuesElement);
42 return 4 + EbmlElement::calculateSizeDenotationLength(size) + size;
54 static const string context(
"parsing \"Cues\"-element");
56 uint64 cuesElementSize = 0, cuePointElementSize, cueTrackPositionsElementSize, cueReferenceElementSize, pos, relPos, statePos;
57 EbmlElement *cueRelativePositionElement, *cueClusterPositionElement;
58 for (
EbmlElement *cuePointElement = cuesElement->
firstChild(); cuePointElement; cuePointElement = cuePointElement->nextSibling()) {
60 cuePointElement->
parse(diag);
61 switch (cuePointElement->id()) {
66 cuePointElementSize = 0;
67 for (
EbmlElement *cuePointChild = cuePointElement->
firstChild(); cuePointChild; cuePointChild = cuePointChild->nextSibling()) {
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 += 2 + EbmlElement::calculateUIntegerLength(pos);
98 m_offsets.emplace(cueTrackPositionsChild, pos);
101 statePos = cueTrackPositionsChild->readUInteger();
102 cueTrackPositionsElementSize += 2 + EbmlElement::calculateUIntegerLength(statePos);
103 m_offsets.emplace(cueTrackPositionsChild, statePos);
106 cueReferenceElementSize = 0;
108 cueReferenceChild = cueReferenceChild->nextSibling()) {
110 cueReferenceChild->parse(diag);
111 switch (cueReferenceChild->id()) {
117 cueReferenceChild->makeBuffer();
118 cueReferenceElementSize += cueReferenceChild->totalSize();
122 statePos = cueReferenceChild->readUInteger();
123 cueReferenceElementSize += 2 + EbmlElement::calculateUIntegerLength(statePos);
124 m_offsets.emplace(cueReferenceChild, statePos);
127 diag.emplace_back(DiagLevel::Warning,
128 "\"CueReference\"-element contains a element which is not known to the parser. It will be ignored.", context);
131 cueTrackPositionsElementSize
132 += 1 + EbmlElement::calculateSizeDenotationLength(cueReferenceElementSize) + cueReferenceElementSize;
133 m_sizes.emplace(cueTrackPositionsChild, cueReferenceElementSize);
136 diag.emplace_back(DiagLevel::Warning,
137 "\"CueTrackPositions\"-element contains a element which is not known to the parser. It will be ignored.", context);
140 if (!cueClusterPositionElement) {
142 DiagLevel::Critical,
"\"CueTrackPositions\"-element does not contain mandatory \"CueClusterPosition\"-element.", context);
143 }
else if (cueRelativePositionElement) {
144 cueTrackPositionsElementSize += 2 + EbmlElement::calculateUIntegerLength(relPos);
145 m_relativeOffsets.emplace(piecewise_construct, forward_as_tuple(cueRelativePositionElement), forward_as_tuple(pos, relPos));
148 += 1 + EbmlElement::calculateSizeDenotationLength(cueTrackPositionsElementSize) + cueTrackPositionsElementSize;
149 m_sizes.emplace(cuePointChild, cueTrackPositionsElementSize);
152 diag.emplace_back(DiagLevel::Warning,
153 "\"CuePoint\"-element contains a element which is not a \"CueTime\"- or a \"CueTrackPositions\"-element. It will be ignored.",
157 cuesElementSize += 1 + EbmlElement::calculateSizeDenotationLength(cuePointElementSize) + cuePointElementSize;
158 m_sizes.emplace(cuePointElement, cuePointElementSize);
162 DiagLevel::Warning,
"\"Cues\"-element contains a element which is not a \"CuePoint\"-element. It will be ignored.", context);
165 m_sizes.emplace(m_cuesElement = cuesElement, cuesElementSize);
172 bool MatroskaCuePositionUpdater::updateOffsets(uint64 originalOffset, uint64 newOffset)
174 bool updated =
false;
175 for (
auto &offset : m_offsets) {
176 if (offset.second.initialValue() == originalOffset && offset.second.currentValue() != newOffset) {
177 updated = updateSize(offset.first->parent(),
178 static_cast<int>(EbmlElement::calculateUIntegerLength(newOffset))
179 - static_cast<int>(EbmlElement::calculateUIntegerLength(offset.second.currentValue())))
181 offset.second.update(newOffset);
191 bool MatroskaCuePositionUpdater::updateRelativeOffsets(uint64 referenceOffset, uint64 originalRelativeOffset, uint64 newRelativeOffset)
193 bool updated =
false;
194 for (
auto &offset : m_relativeOffsets) {
195 if (offset.second.referenceOffset() == referenceOffset && offset.second.initialValue() == originalRelativeOffset
196 && offset.second.currentValue() != newRelativeOffset) {
197 updated = updateSize(offset.first->parent(),
198 static_cast<int>(EbmlElement::calculateUIntegerLength(newRelativeOffset))
199 - static_cast<int>(EbmlElement::calculateUIntegerLength(offset.second.currentValue())))
201 offset.second.update(newRelativeOffset);
211 bool MatroskaCuePositionUpdater::updateSize(
EbmlElement *element,
int shift)
224 uint64 &size = m_sizes.at(element);
226 const uint64 newSize = shift > 0 ? size + static_cast<uint64>(shift) : size - static_cast<uint64>(-shift);
228 const bool updated = updateSize(element->
parent(),
229 shift + static_cast<int>(EbmlElement::calculateSizeDenotationLength(newSize))
230 - static_cast<int>(EbmlElement::calculateSizeDenotationLength(size)));
234 }
catch (
const out_of_range &) {
243 void MatroskaCuePositionUpdater::make(ostream &stream,
Diagnostics &diag)
245 static const string context(
"making \"Cues\"-element");
246 if (!m_cuesElement) {
247 diag.emplace_back(DiagLevel::Warning,
"No cues written; the cues of the source file could not be parsed correctly.", context);
256 stream.write(buff, 4);
257 len = EbmlElement::makeSizeDenotation(m_sizes[m_cuesElement], buff);
258 stream.write(buff, len);
260 for (
EbmlElement *cuePointElement = m_cuesElement->
firstChild(); cuePointElement; cuePointElement = cuePointElement->nextSibling()) {
261 cuePointElement->parse(diag);
262 switch (cuePointElement->id()) {
269 len = EbmlElement::makeSizeDenotation(m_sizes[cuePointElement], buff);
270 stream.write(buff, len);
271 for (
EbmlElement *cuePointChild = cuePointElement->
firstChild(); cuePointChild; cuePointChild = cuePointChild->nextSibling()) {
272 cuePointChild->parse(diag);
273 switch (cuePointChild->id()) {
279 cuePointChild->copyBuffer(stream);
280 cuePointChild->discardBuffer();
286 len = EbmlElement::makeSizeDenotation(m_sizes[cuePointChild], buff);
287 stream.write(buff, len);
289 cueTrackPositionsChild = cueTrackPositionsChild->nextSibling()) {
290 cueTrackPositionsChild->parse(diag);
291 switch (cueTrackPositionsChild->id()) {
296 cueTrackPositionsChild->copyBuffer(stream);
297 cueTrackPositionsChild->discardBuffer();
302 EbmlElement::makeSimpleElement(
303 stream, cueTrackPositionsChild->id(), m_relativeOffsets.at(cueTrackPositionsChild).currentValue());
304 }
catch (
const out_of_range &) {
312 EbmlElement::makeSimpleElement(
313 stream, cueTrackPositionsChild->id(), m_offsets.at(cueTrackPositionsChild).currentValue());
318 len = EbmlElement::makeSizeDenotation(m_sizes[cueTrackPositionsChild], buff);
319 stream.write(buff, len);
321 cueReferenceChild = cueReferenceChild->nextSibling()) {
322 cueReferenceChild->parse(diag);
323 switch (cueReferenceChild->id()) {
330 cueReferenceChild->copyBuffer(stream);
331 cueReferenceChild->discardBuffer();
332 cueReferenceChild->copyEntirely(stream, diag,
nullptr);
337 EbmlElement::makeSimpleElement(
338 stream, cueReferenceChild->id(), m_offsets.at(cueReferenceChild).currentValue());
341 diag.emplace_back(DiagLevel::Warning,
342 "\"CueReference\"-element contains a element which is not known to the parser. It will be ignored.",
348 diag.emplace_back(DiagLevel::Warning,
349 "\"CueTrackPositions\"-element contains a element which is not known to the parser. It will be ignored.",
355 diag.emplace_back(DiagLevel::Warning,
356 "\"CuePoint\"-element contains a element which is not a \"CueTime\"- or a \"CueTrackPositions\"-element. It will be " 364 DiagLevel::Warning,
"\"Cues\"-element contains a element which is not a \"CuePoint\"-element. It will be ignored.", context);
367 }
catch (
const out_of_range &) {
369 DiagLevel::Critical,
"Unable to write the file index because the index of the original file could not be parsed correctly.", context);
ImplementationType * firstChild()
Returns the first child of the element.
The EbmlElement class helps to parse EBML files such as Matroska files.
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.
The Diagnostics class is a container for DiagMessage.
ImplementationType * parent()
Returns the parent of the element.