3030
3131using namespace TagLib ;
3232
33+ namespace {
34+
35+ template <EBML::Element::Id Id, typename ElementType>
36+ std::unique_ptr<ElementType> readElementAt (File &file,
37+ offset_t offset,
38+ offset_t maxOffset)
39+ {
40+ if (offset < 0 || offset >= maxOffset) {
41+ return nullptr ;
42+ }
43+
44+ file.seek (offset);
45+ auto element = EBML::Element::factory (file);
46+ if (!element || element->getId () != Id) {
47+ return nullptr ;
48+ }
49+
50+ auto typed = EBML::element_cast<Id>(std::move (element));
51+ if (!typed || !typed->read (file)) {
52+ return nullptr ;
53+ }
54+ return typed;
55+ }
56+
57+ } // namespace
58+
3359EBML::MkSegment::MkSegment (int sizeLength, offset_t dataSize, offset_t offset):
3460 MasterElement(Id::MkSegment, sizeLength, dataSize, offset)
3561{
@@ -49,16 +75,64 @@ offset_t EBML::MkSegment::segmentDataOffset() const
4975
5076bool EBML::MkSegment::read (File &file)
5177{
52- const offset_t maxOffset = file.tell () + dataSize;
78+ return readLimited (file, dataSize);
79+ }
80+
81+ bool EBML::MkSegment::readLimited (File &file, offset_t scanLimit)
82+ {
83+ const offset_t filePos = file.tell ();
84+ const offset_t maxOffset = filePos + dataSize;
85+ const offset_t maxScanOffset = filePos + std::min (scanLimit, dataSize);
5386 std::unique_ptr<Element> element;
54- int i = 0 ;
55- int seekHeadIndex = -1 ;
56- while ((element = findNextElement (file, maxOffset))) {
87+ while ((element = findNextElement (file, maxScanOffset))) {
5788 if (const Id id = element->getId (); id == Id::MkSeekHead) {
58- seekHeadIndex = i;
5989 seekHead = element_cast<Id::MkSeekHead>(std::move (element));
6090 if (!seekHead->read (file))
6191 return false ;
92+ // We have a seek head, let's use it for faster access to the other elements
93+ if (const auto elementAfterSeekHead = findNextElement (file, maxScanOffset);
94+ elementAfterSeekHead && elementAfterSeekHead->getId () == Id::VoidElement)
95+ seekHead->setPadding (elementAfterSeekHead->getSize ());
96+ const offset_t segDataOffset = segmentDataOffset ();
97+ const auto matroskaSeekHead = parseSeekHead ();
98+ for (const auto &[idValue, relativeOffset] : matroskaSeekHead->entryList ()) {
99+ const offset_t absoluteOffset = segDataOffset + relativeOffset;
100+ switch (static_cast <Id>(idValue)) {
101+ case Id::MkCues:
102+ if (!((cues = readElementAt<Id::MkCues, MkCues>(
103+ file, absoluteOffset, maxOffset))))
104+ return false ;
105+ break ;
106+ case Id::MkInfo:
107+ if (!((info = readElementAt<Id::MkInfo, MkInfo>(
108+ file, absoluteOffset, maxOffset))))
109+ return false ;
110+ break ;
111+ case Id::MkTracks:
112+ if (!((tracks = readElementAt<Id::MkTracks, MkTracks>(
113+ file, absoluteOffset, maxOffset))))
114+ return false ;
115+ break ;
116+ case Id::MkTags:
117+ if (!((tags = readElementAt<Id::MkTags, MkTags>(
118+ file, absoluteOffset, maxOffset))))
119+ return false ;
120+ break ;
121+ case Id::MkAttachments:
122+ if (!((attachments = readElementAt<Id::MkAttachments, MkAttachments>(
123+ file, absoluteOffset, maxOffset))))
124+ return false ;
125+ break ;
126+ case Id::MkChapters:
127+ if (!((chapters = readElementAt<Id::MkChapters, MkChapters>(
128+ file, absoluteOffset, maxOffset))))
129+ return false ;
130+ break ;
131+ default :
132+ break ;
133+ }
134+ }
135+ return true ;
62136 }
63137 else if (id == Id::MkCues) {
64138 cues = element_cast<Id::MkCues>(std::move (element));
@@ -91,14 +165,8 @@ bool EBML::MkSegment::read(File &file)
91165 return false ;
92166 }
93167 else {
94- if (id == Id::VoidElement
95- && seekHead
96- && seekHeadIndex == i - 1 )
97- seekHead->setPadding (element->getSize ());
98-
99168 element->skipData (file);
100169 }
101- i++;
102170 }
103171 return true ;
104172}
0 commit comments