1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS.  All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 
9 #include "mkvparser.hpp"
10 #include <cassert>
11 #include <cstring>
12 #include <new>
13 #include <climits>
14 
15 #ifdef _MSC_VER
16 // Disable MSVC warnings that suggest making code non-portable.
17 #pragma warning(disable : 4996)
18 #endif
19 
~IMkvReader()20 mkvparser::IMkvReader::~IMkvReader() {}
21 
GetVersion(int & major,int & minor,int & build,int & revision)22 void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) {
23   major = 1;
24   minor = 0;
25   build = 0;
26   revision = 28;
27 }
28 
ReadUInt(IMkvReader * pReader,long long pos,long & len)29 long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) {
30   assert(pReader);
31   assert(pos >= 0);
32 
33   int status;
34 
35   //#ifdef _DEBUG
36   //    long long total, available;
37   //    status = pReader->Length(&total, &available);
38   //    assert(status >= 0);
39   //    assert((total < 0) || (available <= total));
40   //    assert(pos < available);
41   //    assert((available - pos) >= 1);  //assume here max u-int len is 8
42   //#endif
43 
44   len = 1;
45 
46   unsigned char b;
47 
48   status = pReader->Read(pos, 1, &b);
49 
50   if (status < 0)  // error or underflow
51     return status;
52 
53   if (status > 0)  // interpreted as "underflow"
54     return E_BUFFER_NOT_FULL;
55 
56   if (b == 0)  // we can't handle u-int values larger than 8 bytes
57     return E_FILE_FORMAT_INVALID;
58 
59   unsigned char m = 0x80;
60 
61   while (!(b & m)) {
62     m >>= 1;
63     ++len;
64   }
65 
66   //#ifdef _DEBUG
67   //    assert((available - pos) >= len);
68   //#endif
69 
70   long long result = b & (~m);
71   ++pos;
72 
73   for (int i = 1; i < len; ++i) {
74     status = pReader->Read(pos, 1, &b);
75 
76     if (status < 0) {
77       len = 1;
78       return status;
79     }
80 
81     if (status > 0) {
82       len = 1;
83       return E_BUFFER_NOT_FULL;
84     }
85 
86     result <<= 8;
87     result |= b;
88 
89     ++pos;
90   }
91 
92   return result;
93 }
94 
GetUIntLength(IMkvReader * pReader,long long pos,long & len)95 long long mkvparser::GetUIntLength(IMkvReader* pReader, long long pos,
96                                    long& len) {
97   assert(pReader);
98   assert(pos >= 0);
99 
100   long long total, available;
101 
102   int status = pReader->Length(&total, &available);
103   assert(status >= 0);
104   assert((total < 0) || (available <= total));
105 
106   len = 1;
107 
108   if (pos >= available)
109     return pos;  // too few bytes available
110 
111   unsigned char b;
112 
113   status = pReader->Read(pos, 1, &b);
114 
115   if (status < 0)
116     return status;
117 
118   assert(status == 0);
119 
120   if (b == 0)  // we can't handle u-int values larger than 8 bytes
121     return E_FILE_FORMAT_INVALID;
122 
123   unsigned char m = 0x80;
124 
125   while (!(b & m)) {
126     m >>= 1;
127     ++len;
128   }
129 
130   return 0;  // success
131 }
132 
133 // TODO(vigneshv): This function assumes that unsigned values never have their
134 // high bit set.
UnserializeUInt(IMkvReader * pReader,long long pos,long long size)135 long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos,
136                                      long long size) {
137   assert(pReader);
138   assert(pos >= 0);
139 
140   if ((size <= 0) || (size > 8))
141     return E_FILE_FORMAT_INVALID;
142 
143   long long result = 0;
144 
145   for (long long i = 0; i < size; ++i) {
146     unsigned char b;
147 
148     const long status = pReader->Read(pos, 1, &b);
149 
150     if (status < 0)
151       return status;
152 
153     result <<= 8;
154     result |= b;
155 
156     ++pos;
157   }
158 
159   return result;
160 }
161 
UnserializeFloat(IMkvReader * pReader,long long pos,long long size_,double & result)162 long mkvparser::UnserializeFloat(IMkvReader* pReader, long long pos,
163                                  long long size_, double& result) {
164   assert(pReader);
165   assert(pos >= 0);
166 
167   if ((size_ != 4) && (size_ != 8))
168     return E_FILE_FORMAT_INVALID;
169 
170   const long size = static_cast<long>(size_);
171 
172   unsigned char buf[8];
173 
174   const int status = pReader->Read(pos, size, buf);
175 
176   if (status < 0)  // error
177     return status;
178 
179   if (size == 4) {
180     union {
181       float f;
182       unsigned long ff;
183     };
184 
185     ff = 0;
186 
187     for (int i = 0;;) {
188       ff |= buf[i];
189 
190       if (++i >= 4)
191         break;
192 
193       ff <<= 8;
194     }
195 
196     result = f;
197   } else {
198     assert(size == 8);
199 
200     union {
201       double d;
202       unsigned long long dd;
203     };
204 
205     dd = 0;
206 
207     for (int i = 0;;) {
208       dd |= buf[i];
209 
210       if (++i >= 8)
211         break;
212 
213       dd <<= 8;
214     }
215 
216     result = d;
217   }
218 
219   return 0;
220 }
221 
UnserializeInt(IMkvReader * pReader,long long pos,long size,long long & result)222 long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos, long size,
223                                long long& result) {
224   assert(pReader);
225   assert(pos >= 0);
226   assert(size > 0);
227   assert(size <= 8);
228 
229   {
230     signed char b;
231 
232     const long status = pReader->Read(pos, 1, (unsigned char*)&b);
233 
234     if (status < 0)
235       return status;
236 
237     result = b;
238 
239     ++pos;
240   }
241 
242   for (long i = 1; i < size; ++i) {
243     unsigned char b;
244 
245     const long status = pReader->Read(pos, 1, &b);
246 
247     if (status < 0)
248       return status;
249 
250     result <<= 8;
251     result |= b;
252 
253     ++pos;
254   }
255 
256   return 0;  // success
257 }
258 
UnserializeString(IMkvReader * pReader,long long pos,long long size_,char * & str)259 long mkvparser::UnserializeString(IMkvReader* pReader, long long pos,
260                                   long long size_, char*& str) {
261   delete[] str;
262   str = NULL;
263 
264   if (size_ >= LONG_MAX)  // we need (size+1) chars
265     return E_FILE_FORMAT_INVALID;
266 
267   const long size = static_cast<long>(size_);
268 
269   str = new (std::nothrow) char[size + 1];
270 
271   if (str == NULL)
272     return -1;
273 
274   unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
275 
276   const long status = pReader->Read(pos, size, buf);
277 
278   if (status) {
279     delete[] str;
280     str = NULL;
281 
282     return status;
283   }
284 
285   str[size] = '\0';
286 
287   return 0;  // success
288 }
289 
ParseElementHeader(IMkvReader * pReader,long long & pos,long long stop,long long & id,long long & size)290 long mkvparser::ParseElementHeader(IMkvReader* pReader, long long& pos,
291                                    long long stop, long long& id,
292                                    long long& size) {
293   if ((stop >= 0) && (pos >= stop))
294     return E_FILE_FORMAT_INVALID;
295 
296   long len;
297 
298   id = ReadUInt(pReader, pos, len);
299 
300   if (id < 0)
301     return E_FILE_FORMAT_INVALID;
302 
303   pos += len;  // consume id
304 
305   if ((stop >= 0) && (pos >= stop))
306     return E_FILE_FORMAT_INVALID;
307 
308   size = ReadUInt(pReader, pos, len);
309 
310   if (size < 0)
311     return E_FILE_FORMAT_INVALID;
312 
313   pos += len;  // consume length of size
314 
315   // pos now designates payload
316 
317   if ((stop >= 0) && ((pos + size) > stop))
318     return E_FILE_FORMAT_INVALID;
319 
320   return 0;  // success
321 }
322 
Match(IMkvReader * pReader,long long & pos,unsigned long id_,long long & val)323 bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_,
324                       long long& val) {
325   assert(pReader);
326   assert(pos >= 0);
327 
328   long long total, available;
329 
330   const long status = pReader->Length(&total, &available);
331   assert(status >= 0);
332   assert((total < 0) || (available <= total));
333   if (status < 0)
334     return false;
335 
336   long len;
337 
338   const long long id = ReadUInt(pReader, pos, len);
339   assert(id >= 0);
340   assert(len > 0);
341   assert(len <= 8);
342   assert((pos + len) <= available);
343 
344   if ((unsigned long)id != id_)
345     return false;
346 
347   pos += len;  // consume id
348 
349   const long long size = ReadUInt(pReader, pos, len);
350   assert(size >= 0);
351   assert(size <= 8);
352   assert(len > 0);
353   assert(len <= 8);
354   assert((pos + len) <= available);
355 
356   pos += len;  // consume length of size of payload
357 
358   val = UnserializeUInt(pReader, pos, size);
359   assert(val >= 0);
360 
361   pos += size;  // consume size of payload
362 
363   return true;
364 }
365 
Match(IMkvReader * pReader,long long & pos,unsigned long id_,unsigned char * & buf,size_t & buflen)366 bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_,
367                       unsigned char*& buf, size_t& buflen) {
368   assert(pReader);
369   assert(pos >= 0);
370 
371   long long total, available;
372 
373   long status = pReader->Length(&total, &available);
374   assert(status >= 0);
375   assert((total < 0) || (available <= total));
376   if (status < 0)
377     return false;
378 
379   long len;
380   const long long id = ReadUInt(pReader, pos, len);
381   assert(id >= 0);
382   assert(len > 0);
383   assert(len <= 8);
384   assert((pos + len) <= available);
385 
386   if ((unsigned long)id != id_)
387     return false;
388 
389   pos += len;  // consume id
390 
391   const long long size_ = ReadUInt(pReader, pos, len);
392   assert(size_ >= 0);
393   assert(len > 0);
394   assert(len <= 8);
395   assert((pos + len) <= available);
396 
397   pos += len;  // consume length of size of payload
398   assert((pos + size_) <= available);
399 
400   const long buflen_ = static_cast<long>(size_);
401 
402   buf = new (std::nothrow) unsigned char[buflen_];
403   assert(buf);  // TODO
404 
405   status = pReader->Read(pos, buflen_, buf);
406   assert(status == 0);  // TODO
407 
408   buflen = buflen_;
409 
410   pos += size_;  // consume size of payload
411   return true;
412 }
413 
414 namespace mkvparser {
415 
EBMLHeader()416 EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
417 
~EBMLHeader()418 EBMLHeader::~EBMLHeader() { delete[] m_docType; }
419 
Init()420 void EBMLHeader::Init() {
421   m_version = 1;
422   m_readVersion = 1;
423   m_maxIdLength = 4;
424   m_maxSizeLength = 8;
425 
426   if (m_docType) {
427     delete[] m_docType;
428     m_docType = NULL;
429   }
430 
431   m_docTypeVersion = 1;
432   m_docTypeReadVersion = 1;
433 }
434 
Parse(IMkvReader * pReader,long long & pos)435 long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
436   assert(pReader);
437 
438   long long total, available;
439 
440   long status = pReader->Length(&total, &available);
441 
442   if (status < 0)  // error
443     return status;
444 
445   pos = 0;
446   long long end = (available >= 1024) ? 1024 : available;
447 
448   for (;;) {
449     unsigned char b = 0;
450 
451     while (pos < end) {
452       status = pReader->Read(pos, 1, &b);
453 
454       if (status < 0)  // error
455         return status;
456 
457       if (b == 0x1A)
458         break;
459 
460       ++pos;
461     }
462 
463     if (b != 0x1A) {
464       if (pos >= 1024)
465         return E_FILE_FORMAT_INVALID;  // don't bother looking anymore
466 
467       if ((total >= 0) && ((total - available) < 5))
468         return E_FILE_FORMAT_INVALID;
469 
470       return available + 5;  // 5 = 4-byte ID + 1st byte of size
471     }
472 
473     if ((total >= 0) && ((total - pos) < 5))
474       return E_FILE_FORMAT_INVALID;
475 
476     if ((available - pos) < 5)
477       return pos + 5;  // try again later
478 
479     long len;
480 
481     const long long result = ReadUInt(pReader, pos, len);
482 
483     if (result < 0)  // error
484       return result;
485 
486     if (result == 0x0A45DFA3) {  // EBML Header ID
487       pos += len;  // consume ID
488       break;
489     }
490 
491     ++pos;  // throw away just the 0x1A byte, and try again
492   }
493 
494   // pos designates start of size field
495 
496   // get length of size field
497 
498   long len;
499   long long result = GetUIntLength(pReader, pos, len);
500 
501   if (result < 0)  // error
502     return result;
503 
504   if (result > 0)  // need more data
505     return result;
506 
507   assert(len > 0);
508   assert(len <= 8);
509 
510   if ((total >= 0) && ((total - pos) < len))
511     return E_FILE_FORMAT_INVALID;
512 
513   if ((available - pos) < len)
514     return pos + len;  // try again later
515 
516   // get the EBML header size
517 
518   result = ReadUInt(pReader, pos, len);
519 
520   if (result < 0)  // error
521     return result;
522 
523   pos += len;  // consume size field
524 
525   // pos now designates start of payload
526 
527   if ((total >= 0) && ((total - pos) < result))
528     return E_FILE_FORMAT_INVALID;
529 
530   if ((available - pos) < result)
531     return pos + result;
532 
533   end = pos + result;
534 
535   Init();
536 
537   while (pos < end) {
538     long long id, size;
539 
540     status = ParseElementHeader(pReader, pos, end, id, size);
541 
542     if (status < 0)  // error
543       return status;
544 
545     if (size == 0)  // weird
546       return E_FILE_FORMAT_INVALID;
547 
548     if (id == 0x0286) {  // version
549       m_version = UnserializeUInt(pReader, pos, size);
550 
551       if (m_version <= 0)
552         return E_FILE_FORMAT_INVALID;
553     } else if (id == 0x02F7) {  // read version
554       m_readVersion = UnserializeUInt(pReader, pos, size);
555 
556       if (m_readVersion <= 0)
557         return E_FILE_FORMAT_INVALID;
558     } else if (id == 0x02F2) {  // max id length
559       m_maxIdLength = UnserializeUInt(pReader, pos, size);
560 
561       if (m_maxIdLength <= 0)
562         return E_FILE_FORMAT_INVALID;
563     } else if (id == 0x02F3) {  // max size length
564       m_maxSizeLength = UnserializeUInt(pReader, pos, size);
565 
566       if (m_maxSizeLength <= 0)
567         return E_FILE_FORMAT_INVALID;
568     } else if (id == 0x0282) {  // doctype
569       if (m_docType)
570         return E_FILE_FORMAT_INVALID;
571 
572       status = UnserializeString(pReader, pos, size, m_docType);
573 
574       if (status)  // error
575         return status;
576     } else if (id == 0x0287) {  // doctype version
577       m_docTypeVersion = UnserializeUInt(pReader, pos, size);
578 
579       if (m_docTypeVersion <= 0)
580         return E_FILE_FORMAT_INVALID;
581     } else if (id == 0x0285) {  // doctype read version
582       m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
583 
584       if (m_docTypeReadVersion <= 0)
585         return E_FILE_FORMAT_INVALID;
586     }
587 
588     pos += size;
589   }
590 
591   assert(pos == end);
592   return 0;
593 }
594 
Segment(IMkvReader * pReader,long long elem_start,long long start,long long size)595 Segment::Segment(IMkvReader* pReader, long long elem_start,
596                  // long long elem_size,
597                  long long start, long long size)
598     : m_pReader(pReader),
599       m_element_start(elem_start),
600       // m_element_size(elem_size),
601       m_start(start),
602       m_size(size),
603       m_pos(start),
604       m_pUnknownSize(0),
605       m_pSeekHead(NULL),
606       m_pInfo(NULL),
607       m_pTracks(NULL),
608       m_pCues(NULL),
609       m_pChapters(NULL),
610       m_clusters(NULL),
611       m_clusterCount(0),
612       m_clusterPreloadCount(0),
613       m_clusterSize(0) {}
614 
~Segment()615 Segment::~Segment() {
616   const long count = m_clusterCount + m_clusterPreloadCount;
617 
618   Cluster** i = m_clusters;
619   Cluster** j = m_clusters + count;
620 
621   while (i != j) {
622     Cluster* const p = *i++;
623     assert(p);
624 
625     delete p;
626   }
627 
628   delete[] m_clusters;
629 
630   delete m_pTracks;
631   delete m_pInfo;
632   delete m_pCues;
633   delete m_pChapters;
634   delete m_pSeekHead;
635 }
636 
CreateInstance(IMkvReader * pReader,long long pos,Segment * & pSegment)637 long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
638                                   Segment*& pSegment) {
639   assert(pReader);
640   assert(pos >= 0);
641 
642   pSegment = NULL;
643 
644   long long total, available;
645 
646   const long status = pReader->Length(&total, &available);
647 
648   if (status < 0)  // error
649     return status;
650 
651   if (available < 0)
652     return -1;
653 
654   if ((total >= 0) && (available > total))
655     return -1;
656 
657   // I would assume that in practice this loop would execute
658   // exactly once, but we allow for other elements (e.g. Void)
659   // to immediately follow the EBML header.  This is fine for
660   // the source filter case (since the entire file is available),
661   // but in the splitter case over a network we should probably
662   // just give up early.  We could for example decide only to
663   // execute this loop a maximum of, say, 10 times.
664   // TODO:
665   // There is an implied "give up early" by only parsing up
666   // to the available limit.  We do do that, but only if the
667   // total file size is unknown.  We could decide to always
668   // use what's available as our limit (irrespective of whether
669   // we happen to know the total file length).  This would have
670   // as its sense "parse this much of the file before giving up",
671   // which a slightly different sense from "try to parse up to
672   // 10 EMBL elements before giving up".
673 
674   for (;;) {
675     if ((total >= 0) && (pos >= total))
676       return E_FILE_FORMAT_INVALID;
677 
678     // Read ID
679     long len;
680     long long result = GetUIntLength(pReader, pos, len);
681 
682     if (result)  // error, or too few available bytes
683       return result;
684 
685     if ((total >= 0) && ((pos + len) > total))
686       return E_FILE_FORMAT_INVALID;
687 
688     if ((pos + len) > available)
689       return pos + len;
690 
691     const long long idpos = pos;
692     const long long id = ReadUInt(pReader, pos, len);
693 
694     if (id < 0)  // error
695       return id;
696 
697     pos += len;  // consume ID
698 
699     // Read Size
700 
701     result = GetUIntLength(pReader, pos, len);
702 
703     if (result)  // error, or too few available bytes
704       return result;
705 
706     if ((total >= 0) && ((pos + len) > total))
707       return E_FILE_FORMAT_INVALID;
708 
709     if ((pos + len) > available)
710       return pos + len;
711 
712     long long size = ReadUInt(pReader, pos, len);
713 
714     if (size < 0)  // error
715       return size;
716 
717     pos += len;  // consume length of size of element
718 
719     // Pos now points to start of payload
720 
721     // Handle "unknown size" for live streaming of webm files.
722     const long long unknown_size = (1LL << (7 * len)) - 1;
723 
724     if (id == 0x08538067) {  // Segment ID
725       if (size == unknown_size)
726         size = -1;
727 
728       else if (total < 0)
729         size = -1;
730 
731       else if ((pos + size) > total)
732         size = -1;
733 
734       pSegment = new (std::nothrow) Segment(pReader, idpos,
735                                             // elem_size
736                                             pos, size);
737 
738       if (pSegment == 0)
739         return -1;  // generic error
740 
741       return 0;  // success
742     }
743 
744     if (size == unknown_size)
745       return E_FILE_FORMAT_INVALID;
746 
747     if ((total >= 0) && ((pos + size) > total))
748       return E_FILE_FORMAT_INVALID;
749 
750     if ((pos + size) > available)
751       return pos + size;
752 
753     pos += size;  // consume payload
754   }
755 }
756 
ParseHeaders()757 long long Segment::ParseHeaders() {
758   // Outermost (level 0) segment object has been constructed,
759   // and pos designates start of payload.  We need to find the
760   // inner (level 1) elements.
761   long long total, available;
762 
763   const int status = m_pReader->Length(&total, &available);
764 
765   if (status < 0)  // error
766     return status;
767 
768   assert((total < 0) || (available <= total));
769 
770   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
771   assert((segment_stop < 0) || (total < 0) || (segment_stop <= total));
772   assert((segment_stop < 0) || (m_pos <= segment_stop));
773 
774   for (;;) {
775     if ((total >= 0) && (m_pos >= total))
776       break;
777 
778     if ((segment_stop >= 0) && (m_pos >= segment_stop))
779       break;
780 
781     long long pos = m_pos;
782     const long long element_start = pos;
783 
784     if ((pos + 1) > available)
785       return (pos + 1);
786 
787     long len;
788     long long result = GetUIntLength(m_pReader, pos, len);
789 
790     if (result < 0)  // error
791       return result;
792 
793     if (result > 0)  // underflow (weird)
794       return (pos + 1);
795 
796     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
797       return E_FILE_FORMAT_INVALID;
798 
799     if ((pos + len) > available)
800       return pos + len;
801 
802     const long long idpos = pos;
803     const long long id = ReadUInt(m_pReader, idpos, len);
804 
805     if (id < 0)  // error
806       return id;
807 
808     if (id == 0x0F43B675)  // Cluster ID
809       break;
810 
811     pos += len;  // consume ID
812 
813     if ((pos + 1) > available)
814       return (pos + 1);
815 
816     // Read Size
817     result = GetUIntLength(m_pReader, pos, len);
818 
819     if (result < 0)  // error
820       return result;
821 
822     if (result > 0)  // underflow (weird)
823       return (pos + 1);
824 
825     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
826       return E_FILE_FORMAT_INVALID;
827 
828     if ((pos + len) > available)
829       return pos + len;
830 
831     const long long size = ReadUInt(m_pReader, pos, len);
832 
833     if (size < 0)  // error
834       return size;
835 
836     pos += len;  // consume length of size of element
837 
838     const long long element_size = size + pos - element_start;
839 
840     // Pos now points to start of payload
841 
842     if ((segment_stop >= 0) && ((pos + size) > segment_stop))
843       return E_FILE_FORMAT_INVALID;
844 
845     // We read EBML elements either in total or nothing at all.
846 
847     if ((pos + size) > available)
848       return pos + size;
849 
850     if (id == 0x0549A966) {  // Segment Info ID
851       if (m_pInfo)
852         return E_FILE_FORMAT_INVALID;
853 
854       m_pInfo = new (std::nothrow)
855           SegmentInfo(this, pos, size, element_start, element_size);
856 
857       if (m_pInfo == NULL)
858         return -1;
859 
860       const long status = m_pInfo->Parse();
861 
862       if (status)
863         return status;
864     } else if (id == 0x0654AE6B) {  // Tracks ID
865       if (m_pTracks)
866         return E_FILE_FORMAT_INVALID;
867 
868       m_pTracks = new (std::nothrow)
869           Tracks(this, pos, size, element_start, element_size);
870 
871       if (m_pTracks == NULL)
872         return -1;
873 
874       const long status = m_pTracks->Parse();
875 
876       if (status)
877         return status;
878     } else if (id == 0x0C53BB6B) {  // Cues ID
879       if (m_pCues == NULL) {
880         m_pCues = new (std::nothrow)
881             Cues(this, pos, size, element_start, element_size);
882 
883         if (m_pCues == NULL)
884           return -1;
885       }
886     } else if (id == 0x014D9B74) {  // SeekHead ID
887       if (m_pSeekHead == NULL) {
888         m_pSeekHead = new (std::nothrow)
889             SeekHead(this, pos, size, element_start, element_size);
890 
891         if (m_pSeekHead == NULL)
892           return -1;
893 
894         const long status = m_pSeekHead->Parse();
895 
896         if (status)
897           return status;
898       }
899     } else if (id == 0x0043A770) {  // Chapters ID
900       if (m_pChapters == NULL) {
901         m_pChapters = new (std::nothrow)
902             Chapters(this, pos, size, element_start, element_size);
903 
904         if (m_pChapters == NULL)
905           return -1;
906 
907         const long status = m_pChapters->Parse();
908 
909         if (status)
910           return status;
911       }
912     }
913 
914     m_pos = pos + size;  // consume payload
915   }
916 
917   assert((segment_stop < 0) || (m_pos <= segment_stop));
918 
919   if (m_pInfo == NULL)  // TODO: liberalize this behavior
920     return E_FILE_FORMAT_INVALID;
921 
922   if (m_pTracks == NULL)
923     return E_FILE_FORMAT_INVALID;
924 
925   return 0;  // success
926 }
927 
LoadCluster(long long & pos,long & len)928 long Segment::LoadCluster(long long& pos, long& len) {
929   for (;;) {
930     const long result = DoLoadCluster(pos, len);
931 
932     if (result <= 1)
933       return result;
934   }
935 }
936 
DoLoadCluster(long long & pos,long & len)937 long Segment::DoLoadCluster(long long& pos, long& len) {
938   if (m_pos < 0)
939     return DoLoadClusterUnknownSize(pos, len);
940 
941   long long total, avail;
942 
943   long status = m_pReader->Length(&total, &avail);
944 
945   if (status < 0)  // error
946     return status;
947 
948   assert((total < 0) || (avail <= total));
949 
950   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
951 
952   long long cluster_off = -1;  // offset relative to start of segment
953   long long cluster_size = -1;  // size of cluster payload
954 
955   for (;;) {
956     if ((total >= 0) && (m_pos >= total))
957       return 1;  // no more clusters
958 
959     if ((segment_stop >= 0) && (m_pos >= segment_stop))
960       return 1;  // no more clusters
961 
962     pos = m_pos;
963 
964     // Read ID
965 
966     if ((pos + 1) > avail) {
967       len = 1;
968       return E_BUFFER_NOT_FULL;
969     }
970 
971     long long result = GetUIntLength(m_pReader, pos, len);
972 
973     if (result < 0)  // error
974       return static_cast<long>(result);
975 
976     if (result > 0)  // weird
977       return E_BUFFER_NOT_FULL;
978 
979     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
980       return E_FILE_FORMAT_INVALID;
981 
982     if ((pos + len) > avail)
983       return E_BUFFER_NOT_FULL;
984 
985     const long long idpos = pos;
986     const long long id = ReadUInt(m_pReader, idpos, len);
987 
988     if (id < 0)  // error (or underflow)
989       return static_cast<long>(id);
990 
991     pos += len;  // consume ID
992 
993     // Read Size
994 
995     if ((pos + 1) > avail) {
996       len = 1;
997       return E_BUFFER_NOT_FULL;
998     }
999 
1000     result = GetUIntLength(m_pReader, pos, len);
1001 
1002     if (result < 0)  // error
1003       return static_cast<long>(result);
1004 
1005     if (result > 0)  // weird
1006       return E_BUFFER_NOT_FULL;
1007 
1008     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1009       return E_FILE_FORMAT_INVALID;
1010 
1011     if ((pos + len) > avail)
1012       return E_BUFFER_NOT_FULL;
1013 
1014     const long long size = ReadUInt(m_pReader, pos, len);
1015 
1016     if (size < 0)  // error
1017       return static_cast<long>(size);
1018 
1019     pos += len;  // consume length of size of element
1020 
1021     // pos now points to start of payload
1022 
1023     if (size == 0) {  // weird
1024       m_pos = pos;
1025       continue;
1026     }
1027 
1028     const long long unknown_size = (1LL << (7 * len)) - 1;
1029 
1030 #if 0  // we must handle this to support live webm
1031         if (size == unknown_size)
1032             return E_FILE_FORMAT_INVALID;  //TODO: allow this
1033 #endif
1034 
1035     if ((segment_stop >= 0) && (size != unknown_size) &&
1036         ((pos + size) > segment_stop)) {
1037       return E_FILE_FORMAT_INVALID;
1038     }
1039 
1040 #if 0  // commented-out, to support incremental cluster parsing
1041         len = static_cast<long>(size);
1042 
1043         if ((pos + size) > avail)
1044             return E_BUFFER_NOT_FULL;
1045 #endif
1046 
1047     if (id == 0x0C53BB6B) {  // Cues ID
1048       if (size == unknown_size)
1049         return E_FILE_FORMAT_INVALID;  // TODO: liberalize
1050 
1051       if (m_pCues == NULL) {
1052         const long long element_size = (pos - idpos) + size;
1053 
1054         m_pCues = new Cues(this, pos, size, idpos, element_size);
1055         assert(m_pCues);  // TODO
1056       }
1057 
1058       m_pos = pos + size;  // consume payload
1059       continue;
1060     }
1061 
1062     if (id != 0x0F43B675) {  // Cluster ID
1063       if (size == unknown_size)
1064         return E_FILE_FORMAT_INVALID;  // TODO: liberalize
1065 
1066       m_pos = pos + size;  // consume payload
1067       continue;
1068     }
1069 
1070     // We have a cluster.
1071 
1072     cluster_off = idpos - m_start;  // relative pos
1073 
1074     if (size != unknown_size)
1075       cluster_size = size;
1076 
1077     break;
1078   }
1079 
1080   assert(cluster_off >= 0);  // have cluster
1081 
1082   long long pos_;
1083   long len_;
1084 
1085   status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_);
1086 
1087   if (status < 0) {  // error, or underflow
1088     pos = pos_;
1089     len = len_;
1090 
1091     return status;
1092   }
1093 
1094   // status == 0 means "no block entries found"
1095   // status > 0 means "found at least one block entry"
1096 
1097   // TODO:
1098   // The issue here is that the segment increments its own
1099   // pos ptr past the most recent cluster parsed, and then
1100   // starts from there to parse the next cluster.  If we
1101   // don't know the size of the current cluster, then we
1102   // must either parse its payload (as we do below), looking
1103   // for the cluster (or cues) ID to terminate the parse.
1104   // This isn't really what we want: rather, we really need
1105   // a way to create the curr cluster object immediately.
1106   // The pity is that cluster::parse can determine its own
1107   // boundary, and we largely duplicate that same logic here.
1108   //
1109   // Maybe we need to get rid of our look-ahead preloading
1110   // in source::parse???
1111   //
1112   // As we're parsing the blocks in the curr cluster
1113   //(in cluster::parse), we should have some way to signal
1114   // to the segment that we have determined the boundary,
1115   // so it can adjust its own segment::m_pos member.
1116   //
1117   // The problem is that we're asserting in asyncreadinit,
1118   // because we adjust the pos down to the curr seek pos,
1119   // and the resulting adjusted len is > 2GB.  I'm suspicious
1120   // that this is even correct, but even if it is, we can't
1121   // be loading that much data in the cache anyway.
1122 
1123   const long idx = m_clusterCount;
1124 
1125   if (m_clusterPreloadCount > 0) {
1126     assert(idx < m_clusterSize);
1127 
1128     Cluster* const pCluster = m_clusters[idx];
1129     assert(pCluster);
1130     assert(pCluster->m_index < 0);
1131 
1132     const long long off = pCluster->GetPosition();
1133     assert(off >= 0);
1134 
1135     if (off == cluster_off) {  // preloaded already
1136       if (status == 0)  // no entries found
1137         return E_FILE_FORMAT_INVALID;
1138 
1139       if (cluster_size >= 0)
1140         pos += cluster_size;
1141       else {
1142         const long long element_size = pCluster->GetElementSize();
1143 
1144         if (element_size <= 0)
1145           return E_FILE_FORMAT_INVALID;  // TODO: handle this case
1146 
1147         pos = pCluster->m_element_start + element_size;
1148       }
1149 
1150       pCluster->m_index = idx;  // move from preloaded to loaded
1151       ++m_clusterCount;
1152       --m_clusterPreloadCount;
1153 
1154       m_pos = pos;  // consume payload
1155       assert((segment_stop < 0) || (m_pos <= segment_stop));
1156 
1157       return 0;  // success
1158     }
1159   }
1160 
1161   if (status == 0) {  // no entries found
1162     if (cluster_size < 0)
1163       return E_FILE_FORMAT_INVALID;  // TODO: handle this
1164 
1165     pos += cluster_size;
1166 
1167     if ((total >= 0) && (pos >= total)) {
1168       m_pos = total;
1169       return 1;  // no more clusters
1170     }
1171 
1172     if ((segment_stop >= 0) && (pos >= segment_stop)) {
1173       m_pos = segment_stop;
1174       return 1;  // no more clusters
1175     }
1176 
1177     m_pos = pos;
1178     return 2;  // try again
1179   }
1180 
1181   // status > 0 means we have an entry
1182 
1183   Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
1184   // element_size);
1185   assert(pCluster);
1186 
1187   AppendCluster(pCluster);
1188   assert(m_clusters);
1189   assert(idx < m_clusterSize);
1190   assert(m_clusters[idx] == pCluster);
1191 
1192   if (cluster_size >= 0) {
1193     pos += cluster_size;
1194 
1195     m_pos = pos;
1196     assert((segment_stop < 0) || (m_pos <= segment_stop));
1197 
1198     return 0;
1199   }
1200 
1201   m_pUnknownSize = pCluster;
1202   m_pos = -pos;
1203 
1204   return 0;  // partial success, since we have a new cluster
1205 
1206 // status == 0 means "no block entries found"
1207 
1208 // pos designates start of payload
1209 // m_pos has NOT been adjusted yet (in case we need to come back here)
1210 
1211 #if 0
1212 
1213     if (cluster_size < 0) {  //unknown size
1214         const long long payload_pos = pos;  //absolute pos of cluster payload
1215 
1216         for (;;) {  //determine cluster size
1217             if ((total >= 0) && (pos >= total))
1218                 break;
1219 
1220             if ((segment_stop >= 0) && (pos >= segment_stop))
1221                 break;  //no more clusters
1222 
1223             //Read ID
1224 
1225             if ((pos + 1) > avail)
1226             {
1227                 len = 1;
1228                 return E_BUFFER_NOT_FULL;
1229             }
1230 
1231             long long result = GetUIntLength(m_pReader, pos, len);
1232 
1233             if (result < 0)  //error
1234                 return static_cast<long>(result);
1235 
1236             if (result > 0)  //weird
1237                 return E_BUFFER_NOT_FULL;
1238 
1239             if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1240                 return E_FILE_FORMAT_INVALID;
1241 
1242             if ((pos + len) > avail)
1243                 return E_BUFFER_NOT_FULL;
1244 
1245             const long long idpos = pos;
1246             const long long id = ReadUInt(m_pReader, idpos, len);
1247 
1248             if (id < 0)  //error (or underflow)
1249                 return static_cast<long>(id);
1250 
1251             //This is the distinguished set of ID's we use to determine
1252             //that we have exhausted the sub-element's inside the cluster
1253             //whose ID we parsed earlier.
1254 
1255             if (id == 0x0F43B675)  //Cluster ID
1256                 break;
1257 
1258             if (id == 0x0C53BB6B)  //Cues ID
1259                 break;
1260 
1261             switch (id)
1262             {
1263                 case 0x20:  //BlockGroup
1264                 case 0x23:  //Simple Block
1265                 case 0x67:  //TimeCode
1266                 case 0x2B:  //PrevSize
1267                     break;
1268 
1269                 default:
1270                     assert(false);
1271                     break;
1272             }
1273 
1274             pos += len;  //consume ID (of sub-element)
1275 
1276             //Read Size
1277 
1278             if ((pos + 1) > avail)
1279             {
1280                 len = 1;
1281                 return E_BUFFER_NOT_FULL;
1282             }
1283 
1284             result = GetUIntLength(m_pReader, pos, len);
1285 
1286             if (result < 0)  //error
1287                 return static_cast<long>(result);
1288 
1289             if (result > 0)  //weird
1290                 return E_BUFFER_NOT_FULL;
1291 
1292             if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1293                 return E_FILE_FORMAT_INVALID;
1294 
1295             if ((pos + len) > avail)
1296                 return E_BUFFER_NOT_FULL;
1297 
1298             const long long size = ReadUInt(m_pReader, pos, len);
1299 
1300             if (size < 0)  //error
1301                 return static_cast<long>(size);
1302 
1303             pos += len;  //consume size field of element
1304 
1305             //pos now points to start of sub-element's payload
1306 
1307             if (size == 0)  //weird
1308                 continue;
1309 
1310             const long long unknown_size = (1LL << (7 * len)) - 1;
1311 
1312             if (size == unknown_size)
1313                 return E_FILE_FORMAT_INVALID;  //not allowed for sub-elements
1314 
1315             if ((segment_stop >= 0) && ((pos + size) > segment_stop))  //weird
1316                 return E_FILE_FORMAT_INVALID;
1317 
1318             pos += size;  //consume payload of sub-element
1319             assert((segment_stop < 0) || (pos <= segment_stop));
1320         }  //determine cluster size
1321 
1322         cluster_size = pos - payload_pos;
1323         assert(cluster_size >= 0);
1324 
1325         pos = payload_pos;  //reset and re-parse original cluster
1326     }
1327 
1328     if (m_clusterPreloadCount > 0)
1329     {
1330         assert(idx < m_clusterSize);
1331 
1332         Cluster* const pCluster = m_clusters[idx];
1333         assert(pCluster);
1334         assert(pCluster->m_index < 0);
1335 
1336         const long long off = pCluster->GetPosition();
1337         assert(off >= 0);
1338 
1339         if (off == cluster_off)  //preloaded already
1340             return E_FILE_FORMAT_INVALID;  //subtle
1341     }
1342 
1343     m_pos = pos + cluster_size;  //consume payload
1344     assert((segment_stop < 0) || (m_pos <= segment_stop));
1345 
1346     return 2;     //try to find another cluster
1347 
1348 #endif
1349 }
1350 
DoLoadClusterUnknownSize(long long & pos,long & len)1351 long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
1352   assert(m_pos < 0);
1353   assert(m_pUnknownSize);
1354 
1355 #if 0
1356     assert(m_pUnknownSize->GetElementSize() < 0);  //TODO: verify this
1357 
1358     const long long element_start = m_pUnknownSize->m_element_start;
1359 
1360     pos = -m_pos;
1361     assert(pos > element_start);
1362 
1363     //We have already consumed the (cluster) ID and size fields.
1364     //We just need to consume the blocks and other sub-elements
1365     //of this cluster, until we discover the boundary.
1366 
1367     long long total, avail;
1368 
1369     long status = m_pReader->Length(&total, &avail);
1370 
1371     if (status < 0)  //error
1372         return status;
1373 
1374     assert((total < 0) || (avail <= total));
1375 
1376     const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1377 
1378     long long element_size = -1;
1379 
1380     for (;;) {  //determine cluster size
1381         if ((total >= 0) && (pos >= total))
1382         {
1383             element_size = total - element_start;
1384             assert(element_size > 0);
1385 
1386             break;
1387         }
1388 
1389         if ((segment_stop >= 0) && (pos >= segment_stop))
1390         {
1391             element_size = segment_stop - element_start;
1392             assert(element_size > 0);
1393 
1394             break;
1395         }
1396 
1397         //Read ID
1398 
1399         if ((pos + 1) > avail)
1400         {
1401             len = 1;
1402             return E_BUFFER_NOT_FULL;
1403         }
1404 
1405         long long result = GetUIntLength(m_pReader, pos, len);
1406 
1407         if (result < 0)  //error
1408             return static_cast<long>(result);
1409 
1410         if (result > 0)  //weird
1411             return E_BUFFER_NOT_FULL;
1412 
1413         if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1414             return E_FILE_FORMAT_INVALID;
1415 
1416         if ((pos + len) > avail)
1417             return E_BUFFER_NOT_FULL;
1418 
1419         const long long idpos = pos;
1420         const long long id = ReadUInt(m_pReader, idpos, len);
1421 
1422         if (id < 0)  //error (or underflow)
1423             return static_cast<long>(id);
1424 
1425         //This is the distinguished set of ID's we use to determine
1426         //that we have exhausted the sub-element's inside the cluster
1427         //whose ID we parsed earlier.
1428 
1429         if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) {  //Cluster ID or Cues ID
1430             element_size = pos - element_start;
1431             assert(element_size > 0);
1432 
1433             break;
1434         }
1435 
1436 #ifdef _DEBUG
1437         switch (id)
1438         {
1439             case 0x20:  //BlockGroup
1440             case 0x23:  //Simple Block
1441             case 0x67:  //TimeCode
1442             case 0x2B:  //PrevSize
1443                 break;
1444 
1445             default:
1446                 assert(false);
1447                 break;
1448         }
1449 #endif
1450 
1451         pos += len;  //consume ID (of sub-element)
1452 
1453         //Read Size
1454 
1455         if ((pos + 1) > avail)
1456         {
1457             len = 1;
1458             return E_BUFFER_NOT_FULL;
1459         }
1460 
1461         result = GetUIntLength(m_pReader, pos, len);
1462 
1463         if (result < 0)  //error
1464             return static_cast<long>(result);
1465 
1466         if (result > 0)  //weird
1467             return E_BUFFER_NOT_FULL;
1468 
1469         if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1470             return E_FILE_FORMAT_INVALID;
1471 
1472         if ((pos + len) > avail)
1473             return E_BUFFER_NOT_FULL;
1474 
1475         const long long size = ReadUInt(m_pReader, pos, len);
1476 
1477         if (size < 0)  //error
1478             return static_cast<long>(size);
1479 
1480         pos += len;  //consume size field of element
1481 
1482         //pos now points to start of sub-element's payload
1483 
1484         if (size == 0)  //weird
1485             continue;
1486 
1487         const long long unknown_size = (1LL << (7 * len)) - 1;
1488 
1489         if (size == unknown_size)
1490             return E_FILE_FORMAT_INVALID;  //not allowed for sub-elements
1491 
1492         if ((segment_stop >= 0) && ((pos + size) > segment_stop))  //weird
1493             return E_FILE_FORMAT_INVALID;
1494 
1495         pos += size;  //consume payload of sub-element
1496         assert((segment_stop < 0) || (pos <= segment_stop));
1497     }  //determine cluster size
1498 
1499     assert(element_size >= 0);
1500 
1501     m_pos = element_start + element_size;
1502     m_pUnknownSize = 0;
1503 
1504     return 2;  //continue parsing
1505 #else
1506   const long status = m_pUnknownSize->Parse(pos, len);
1507 
1508   if (status < 0)  // error or underflow
1509     return status;
1510 
1511   if (status == 0)  // parsed a block
1512     return 2;  // continue parsing
1513 
1514   assert(status > 0);  // nothing left to parse of this cluster
1515 
1516   const long long start = m_pUnknownSize->m_element_start;
1517 
1518   const long long size = m_pUnknownSize->GetElementSize();
1519   assert(size >= 0);
1520 
1521   pos = start + size;
1522   m_pos = pos;
1523 
1524   m_pUnknownSize = 0;
1525 
1526   return 2;  // continue parsing
1527 #endif
1528 }
1529 
AppendCluster(Cluster * pCluster)1530 void Segment::AppendCluster(Cluster* pCluster) {
1531   assert(pCluster);
1532   assert(pCluster->m_index >= 0);
1533 
1534   const long count = m_clusterCount + m_clusterPreloadCount;
1535 
1536   long& size = m_clusterSize;
1537   assert(size >= count);
1538 
1539   const long idx = pCluster->m_index;
1540   assert(idx == m_clusterCount);
1541 
1542   if (count >= size) {
1543     const long n = (size <= 0) ? 2048 : 2 * size;
1544 
1545     Cluster** const qq = new Cluster* [n];
1546     Cluster** q = qq;
1547 
1548     Cluster** p = m_clusters;
1549     Cluster** const pp = p + count;
1550 
1551     while (p != pp)
1552       *q++ = *p++;
1553 
1554     delete[] m_clusters;
1555 
1556     m_clusters = qq;
1557     size = n;
1558   }
1559 
1560   if (m_clusterPreloadCount > 0) {
1561     assert(m_clusters);
1562 
1563     Cluster** const p = m_clusters + m_clusterCount;
1564     assert(*p);
1565     assert((*p)->m_index < 0);
1566 
1567     Cluster** q = p + m_clusterPreloadCount;
1568     assert(q < (m_clusters + size));
1569 
1570     for (;;) {
1571       Cluster** const qq = q - 1;
1572       assert((*qq)->m_index < 0);
1573 
1574       *q = *qq;
1575       q = qq;
1576 
1577       if (q == p)
1578         break;
1579     }
1580   }
1581 
1582   m_clusters[idx] = pCluster;
1583   ++m_clusterCount;
1584 }
1585 
PreloadCluster(Cluster * pCluster,ptrdiff_t idx)1586 void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
1587   assert(pCluster);
1588   assert(pCluster->m_index < 0);
1589   assert(idx >= m_clusterCount);
1590 
1591   const long count = m_clusterCount + m_clusterPreloadCount;
1592 
1593   long& size = m_clusterSize;
1594   assert(size >= count);
1595 
1596   if (count >= size) {
1597     const long n = (size <= 0) ? 2048 : 2 * size;
1598 
1599     Cluster** const qq = new Cluster* [n];
1600     Cluster** q = qq;
1601 
1602     Cluster** p = m_clusters;
1603     Cluster** const pp = p + count;
1604 
1605     while (p != pp)
1606       *q++ = *p++;
1607 
1608     delete[] m_clusters;
1609 
1610     m_clusters = qq;
1611     size = n;
1612   }
1613 
1614   assert(m_clusters);
1615 
1616   Cluster** const p = m_clusters + idx;
1617 
1618   Cluster** q = m_clusters + count;
1619   assert(q >= p);
1620   assert(q < (m_clusters + size));
1621 
1622   while (q > p) {
1623     Cluster** const qq = q - 1;
1624     assert((*qq)->m_index < 0);
1625 
1626     *q = *qq;
1627     q = qq;
1628   }
1629 
1630   m_clusters[idx] = pCluster;
1631   ++m_clusterPreloadCount;
1632 }
1633 
Load()1634 long Segment::Load() {
1635   assert(m_clusters == NULL);
1636   assert(m_clusterSize == 0);
1637   assert(m_clusterCount == 0);
1638   // assert(m_size >= 0);
1639 
1640   // Outermost (level 0) segment object has been constructed,
1641   // and pos designates start of payload.  We need to find the
1642   // inner (level 1) elements.
1643 
1644   const long long header_status = ParseHeaders();
1645 
1646   if (header_status < 0)  // error
1647     return static_cast<long>(header_status);
1648 
1649   if (header_status > 0)  // underflow
1650     return E_BUFFER_NOT_FULL;
1651 
1652   assert(m_pInfo);
1653   assert(m_pTracks);
1654 
1655   for (;;) {
1656     const int status = LoadCluster();
1657 
1658     if (status < 0)  // error
1659       return status;
1660 
1661     if (status >= 1)  // no more clusters
1662       return 0;
1663   }
1664 }
1665 
SeekHead(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)1666 SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
1667                    long long element_start, long long element_size)
1668     : m_pSegment(pSegment),
1669       m_start(start),
1670       m_size(size_),
1671       m_element_start(element_start),
1672       m_element_size(element_size),
1673       m_entries(0),
1674       m_entry_count(0),
1675       m_void_elements(0),
1676       m_void_element_count(0) {}
1677 
~SeekHead()1678 SeekHead::~SeekHead() {
1679   delete[] m_entries;
1680   delete[] m_void_elements;
1681 }
1682 
Parse()1683 long SeekHead::Parse() {
1684   IMkvReader* const pReader = m_pSegment->m_pReader;
1685 
1686   long long pos = m_start;
1687   const long long stop = m_start + m_size;
1688 
1689   // first count the seek head entries
1690 
1691   int entry_count = 0;
1692   int void_element_count = 0;
1693 
1694   while (pos < stop) {
1695     long long id, size;
1696 
1697     const long status = ParseElementHeader(pReader, pos, stop, id, size);
1698 
1699     if (status < 0)  // error
1700       return status;
1701 
1702     if (id == 0x0DBB)  // SeekEntry ID
1703       ++entry_count;
1704     else if (id == 0x6C)  // Void ID
1705       ++void_element_count;
1706 
1707     pos += size;  // consume payload
1708     assert(pos <= stop);
1709   }
1710 
1711   assert(pos == stop);
1712 
1713   m_entries = new (std::nothrow) Entry[entry_count];
1714 
1715   if (m_entries == NULL)
1716     return -1;
1717 
1718   m_void_elements = new (std::nothrow) VoidElement[void_element_count];
1719 
1720   if (m_void_elements == NULL)
1721     return -1;
1722 
1723   // now parse the entries and void elements
1724 
1725   Entry* pEntry = m_entries;
1726   VoidElement* pVoidElement = m_void_elements;
1727 
1728   pos = m_start;
1729 
1730   while (pos < stop) {
1731     const long long idpos = pos;
1732 
1733     long long id, size;
1734 
1735     const long status = ParseElementHeader(pReader, pos, stop, id, size);
1736 
1737     if (status < 0)  // error
1738       return status;
1739 
1740     if (id == 0x0DBB) {  // SeekEntry ID
1741       if (ParseEntry(pReader, pos, size, pEntry)) {
1742         Entry& e = *pEntry++;
1743 
1744         e.element_start = idpos;
1745         e.element_size = (pos + size) - idpos;
1746       }
1747     } else if (id == 0x6C) {  // Void ID
1748       VoidElement& e = *pVoidElement++;
1749 
1750       e.element_start = idpos;
1751       e.element_size = (pos + size) - idpos;
1752     }
1753 
1754     pos += size;  // consume payload
1755     assert(pos <= stop);
1756   }
1757 
1758   assert(pos == stop);
1759 
1760   ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
1761   assert(count_ >= 0);
1762   assert(count_ <= entry_count);
1763 
1764   m_entry_count = static_cast<int>(count_);
1765 
1766   count_ = ptrdiff_t(pVoidElement - m_void_elements);
1767   assert(count_ >= 0);
1768   assert(count_ <= void_element_count);
1769 
1770   m_void_element_count = static_cast<int>(count_);
1771 
1772   return 0;
1773 }
1774 
GetCount() const1775 int SeekHead::GetCount() const { return m_entry_count; }
1776 
GetEntry(int idx) const1777 const SeekHead::Entry* SeekHead::GetEntry(int idx) const {
1778   if (idx < 0)
1779     return 0;
1780 
1781   if (idx >= m_entry_count)
1782     return 0;
1783 
1784   return m_entries + idx;
1785 }
1786 
GetVoidElementCount() const1787 int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
1788 
GetVoidElement(int idx) const1789 const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const {
1790   if (idx < 0)
1791     return 0;
1792 
1793   if (idx >= m_void_element_count)
1794     return 0;
1795 
1796   return m_void_elements + idx;
1797 }
1798 
1799 #if 0
1800 void Segment::ParseCues(long long off)
1801 {
1802     if (m_pCues)
1803         return;
1804 
1805     //odbgstream os;
1806     //os << "Segment::ParseCues (begin)" << endl;
1807 
1808     long long pos = m_start + off;
1809     const long long element_start = pos;
1810     const long long stop = m_start + m_size;
1811 
1812     long len;
1813 
1814     long long result = GetUIntLength(m_pReader, pos, len);
1815     assert(result == 0);
1816     assert((pos + len) <= stop);
1817 
1818     const long long idpos = pos;
1819 
1820     const long long id = ReadUInt(m_pReader, idpos, len);
1821     assert(id == 0x0C53BB6B);  //Cues ID
1822 
1823     pos += len;  //consume ID
1824     assert(pos < stop);
1825 
1826     //Read Size
1827 
1828     result = GetUIntLength(m_pReader, pos, len);
1829     assert(result == 0);
1830     assert((pos + len) <= stop);
1831 
1832     const long long size = ReadUInt(m_pReader, pos, len);
1833     assert(size >= 0);
1834 
1835     pos += len;  //consume length of size of element
1836     assert((pos + size) <= stop);
1837 
1838     const long long element_size = size + pos - element_start;
1839 
1840     //Pos now points to start of payload
1841 
1842     m_pCues = new Cues(this, pos, size, element_start, element_size);
1843     assert(m_pCues);  //TODO
1844 
1845     //os << "Segment::ParseCues (end)" << endl;
1846 }
1847 #else
ParseCues(long long off,long long & pos,long & len)1848 long Segment::ParseCues(long long off, long long& pos, long& len) {
1849   if (m_pCues)
1850     return 0;  // success
1851 
1852   if (off < 0)
1853     return -1;
1854 
1855   long long total, avail;
1856 
1857   const int status = m_pReader->Length(&total, &avail);
1858 
1859   if (status < 0)  // error
1860     return status;
1861 
1862   assert((total < 0) || (avail <= total));
1863 
1864   pos = m_start + off;
1865 
1866   if ((total < 0) || (pos >= total))
1867     return 1;  // don't bother parsing cues
1868 
1869   const long long element_start = pos;
1870   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1871 
1872   if ((pos + 1) > avail) {
1873     len = 1;
1874     return E_BUFFER_NOT_FULL;
1875   }
1876 
1877   long long result = GetUIntLength(m_pReader, pos, len);
1878 
1879   if (result < 0)  // error
1880     return static_cast<long>(result);
1881 
1882   if (result > 0)  // underflow (weird)
1883   {
1884     len = 1;
1885     return E_BUFFER_NOT_FULL;
1886   }
1887 
1888   if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1889     return E_FILE_FORMAT_INVALID;
1890 
1891   if ((pos + len) > avail)
1892     return E_BUFFER_NOT_FULL;
1893 
1894   const long long idpos = pos;
1895 
1896   const long long id = ReadUInt(m_pReader, idpos, len);
1897 
1898   if (id != 0x0C53BB6B)  // Cues ID
1899     return E_FILE_FORMAT_INVALID;
1900 
1901   pos += len;  // consume ID
1902   assert((segment_stop < 0) || (pos <= segment_stop));
1903 
1904   // Read Size
1905 
1906   if ((pos + 1) > avail) {
1907     len = 1;
1908     return E_BUFFER_NOT_FULL;
1909   }
1910 
1911   result = GetUIntLength(m_pReader, pos, len);
1912 
1913   if (result < 0)  // error
1914     return static_cast<long>(result);
1915 
1916   if (result > 0)  // underflow (weird)
1917   {
1918     len = 1;
1919     return E_BUFFER_NOT_FULL;
1920   }
1921 
1922   if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1923     return E_FILE_FORMAT_INVALID;
1924 
1925   if ((pos + len) > avail)
1926     return E_BUFFER_NOT_FULL;
1927 
1928   const long long size = ReadUInt(m_pReader, pos, len);
1929 
1930   if (size < 0)  // error
1931     return static_cast<long>(size);
1932 
1933   if (size == 0)  // weird, although technically not illegal
1934     return 1;  // done
1935 
1936   pos += len;  // consume length of size of element
1937   assert((segment_stop < 0) || (pos <= segment_stop));
1938 
1939   // Pos now points to start of payload
1940 
1941   const long long element_stop = pos + size;
1942 
1943   if ((segment_stop >= 0) && (element_stop > segment_stop))
1944     return E_FILE_FORMAT_INVALID;
1945 
1946   if ((total >= 0) && (element_stop > total))
1947     return 1;  // don't bother parsing anymore
1948 
1949   len = static_cast<long>(size);
1950 
1951   if (element_stop > avail)
1952     return E_BUFFER_NOT_FULL;
1953 
1954   const long long element_size = element_stop - element_start;
1955 
1956   m_pCues =
1957       new (std::nothrow) Cues(this, pos, size, element_start, element_size);
1958   assert(m_pCues);  // TODO
1959 
1960   return 0;  // success
1961 }
1962 #endif
1963 
1964 #if 0
1965 void Segment::ParseSeekEntry(
1966     long long start,
1967     long long size_)
1968 {
1969     long long pos = start;
1970 
1971     const long long stop = start + size_;
1972 
1973     long len;
1974 
1975     const long long seekIdId = ReadUInt(m_pReader, pos, len);
1976     //seekIdId;
1977     assert(seekIdId == 0x13AB);  //SeekID ID
1978     assert((pos + len) <= stop);
1979 
1980     pos += len;  //consume id
1981 
1982     const long long seekIdSize = ReadUInt(m_pReader, pos, len);
1983     assert(seekIdSize >= 0);
1984     assert((pos + len) <= stop);
1985 
1986     pos += len;  //consume size
1987 
1988     const long long seekId = ReadUInt(m_pReader, pos, len);  //payload
1989     assert(seekId >= 0);
1990     assert(len == seekIdSize);
1991     assert((pos + len) <= stop);
1992 
1993     pos += seekIdSize;  //consume payload
1994 
1995     const long long seekPosId = ReadUInt(m_pReader, pos, len);
1996     //seekPosId;
1997     assert(seekPosId == 0x13AC);  //SeekPos ID
1998     assert((pos + len) <= stop);
1999 
2000     pos += len;  //consume id
2001 
2002     const long long seekPosSize = ReadUInt(m_pReader, pos, len);
2003     assert(seekPosSize >= 0);
2004     assert((pos + len) <= stop);
2005 
2006     pos += len;  //consume size
2007     assert((pos + seekPosSize) <= stop);
2008 
2009     const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize);
2010     assert(seekOff >= 0);
2011     assert(seekOff < m_size);
2012 
2013     pos += seekPosSize;  //consume payload
2014     assert(pos == stop);
2015 
2016     const long long seekPos = m_start + seekOff;
2017     assert(seekPos < (m_start + m_size));
2018 
2019     if (seekId == 0x0C53BB6B)  //Cues ID
2020         ParseCues(seekOff);
2021 }
2022 #else
ParseEntry(IMkvReader * pReader,long long start,long long size_,Entry * pEntry)2023 bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
2024                           Entry* pEntry) {
2025   if (size_ <= 0)
2026     return false;
2027 
2028   long long pos = start;
2029   const long long stop = start + size_;
2030 
2031   long len;
2032 
2033   // parse the container for the level-1 element ID
2034 
2035   const long long seekIdId = ReadUInt(pReader, pos, len);
2036   // seekIdId;
2037 
2038   if (seekIdId != 0x13AB)  // SeekID ID
2039     return false;
2040 
2041   if ((pos + len) > stop)
2042     return false;
2043 
2044   pos += len;  // consume SeekID id
2045 
2046   const long long seekIdSize = ReadUInt(pReader, pos, len);
2047 
2048   if (seekIdSize <= 0)
2049     return false;
2050 
2051   if ((pos + len) > stop)
2052     return false;
2053 
2054   pos += len;  // consume size of field
2055 
2056   if ((pos + seekIdSize) > stop)
2057     return false;
2058 
2059   // Note that the SeekId payload really is serialized
2060   // as a "Matroska integer", not as a plain binary value.
2061   // In fact, Matroska requires that ID values in the
2062   // stream exactly match the binary representation as listed
2063   // in the Matroska specification.
2064   //
2065   // This parser is more liberal, and permits IDs to have
2066   // any width.  (This could make the representation in the stream
2067   // different from what's in the spec, but it doesn't matter here,
2068   // since we always normalize "Matroska integer" values.)
2069 
2070   pEntry->id = ReadUInt(pReader, pos, len);  // payload
2071 
2072   if (pEntry->id <= 0)
2073     return false;
2074 
2075   if (len != seekIdSize)
2076     return false;
2077 
2078   pos += seekIdSize;  // consume SeekID payload
2079 
2080   const long long seekPosId = ReadUInt(pReader, pos, len);
2081 
2082   if (seekPosId != 0x13AC)  // SeekPos ID
2083     return false;
2084 
2085   if ((pos + len) > stop)
2086     return false;
2087 
2088   pos += len;  // consume id
2089 
2090   const long long seekPosSize = ReadUInt(pReader, pos, len);
2091 
2092   if (seekPosSize <= 0)
2093     return false;
2094 
2095   if ((pos + len) > stop)
2096     return false;
2097 
2098   pos += len;  // consume size
2099 
2100   if ((pos + seekPosSize) > stop)
2101     return false;
2102 
2103   pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
2104 
2105   if (pEntry->pos < 0)
2106     return false;
2107 
2108   pos += seekPosSize;  // consume payload
2109 
2110   if (pos != stop)
2111     return false;
2112 
2113   return true;
2114 }
2115 #endif
2116 
Cues(Segment * pSegment,long long start_,long long size_,long long element_start,long long element_size)2117 Cues::Cues(Segment* pSegment, long long start_, long long size_,
2118            long long element_start, long long element_size)
2119     : m_pSegment(pSegment),
2120       m_start(start_),
2121       m_size(size_),
2122       m_element_start(element_start),
2123       m_element_size(element_size),
2124       m_cue_points(NULL),
2125       m_count(0),
2126       m_preload_count(0),
2127       m_pos(start_) {}
2128 
~Cues()2129 Cues::~Cues() {
2130   const long n = m_count + m_preload_count;
2131 
2132   CuePoint** p = m_cue_points;
2133   CuePoint** const q = p + n;
2134 
2135   while (p != q) {
2136     CuePoint* const pCP = *p++;
2137     assert(pCP);
2138 
2139     delete pCP;
2140   }
2141 
2142   delete[] m_cue_points;
2143 }
2144 
GetCount() const2145 long Cues::GetCount() const {
2146   if (m_cue_points == NULL)
2147     return -1;
2148 
2149   return m_count;  // TODO: really ignore preload count?
2150 }
2151 
DoneParsing() const2152 bool Cues::DoneParsing() const {
2153   const long long stop = m_start + m_size;
2154   return (m_pos >= stop);
2155 }
2156 
Init() const2157 void Cues::Init() const {
2158   if (m_cue_points)
2159     return;
2160 
2161   assert(m_count == 0);
2162   assert(m_preload_count == 0);
2163 
2164   IMkvReader* const pReader = m_pSegment->m_pReader;
2165 
2166   const long long stop = m_start + m_size;
2167   long long pos = m_start;
2168 
2169   long cue_points_size = 0;
2170 
2171   while (pos < stop) {
2172     const long long idpos = pos;
2173 
2174     long len;
2175 
2176     const long long id = ReadUInt(pReader, pos, len);
2177     assert(id >= 0);  // TODO
2178     assert((pos + len) <= stop);
2179 
2180     pos += len;  // consume ID
2181 
2182     const long long size = ReadUInt(pReader, pos, len);
2183     assert(size >= 0);
2184     assert((pos + len) <= stop);
2185 
2186     pos += len;  // consume Size field
2187     assert((pos + size) <= stop);
2188 
2189     if (id == 0x3B)  // CuePoint ID
2190       PreloadCuePoint(cue_points_size, idpos);
2191 
2192     pos += size;  // consume payload
2193     assert(pos <= stop);
2194   }
2195 }
2196 
PreloadCuePoint(long & cue_points_size,long long pos) const2197 void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
2198   assert(m_count == 0);
2199 
2200   if (m_preload_count >= cue_points_size) {
2201     const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
2202 
2203     CuePoint** const qq = new CuePoint* [n];
2204     CuePoint** q = qq;  // beginning of target
2205 
2206     CuePoint** p = m_cue_points;  // beginning of source
2207     CuePoint** const pp = p + m_preload_count;  // end of source
2208 
2209     while (p != pp)
2210       *q++ = *p++;
2211 
2212     delete[] m_cue_points;
2213 
2214     m_cue_points = qq;
2215     cue_points_size = n;
2216   }
2217 
2218   CuePoint* const pCP = new CuePoint(m_preload_count, pos);
2219   m_cue_points[m_preload_count++] = pCP;
2220 }
2221 
LoadCuePoint() const2222 bool Cues::LoadCuePoint() const {
2223   // odbgstream os;
2224   // os << "Cues::LoadCuePoint" << endl;
2225 
2226   const long long stop = m_start + m_size;
2227 
2228   if (m_pos >= stop)
2229     return false;  // nothing else to do
2230 
2231   Init();
2232 
2233   IMkvReader* const pReader = m_pSegment->m_pReader;
2234 
2235   while (m_pos < stop) {
2236     const long long idpos = m_pos;
2237 
2238     long len;
2239 
2240     const long long id = ReadUInt(pReader, m_pos, len);
2241     assert(id >= 0);  // TODO
2242     assert((m_pos + len) <= stop);
2243 
2244     m_pos += len;  // consume ID
2245 
2246     const long long size = ReadUInt(pReader, m_pos, len);
2247     assert(size >= 0);
2248     assert((m_pos + len) <= stop);
2249 
2250     m_pos += len;  // consume Size field
2251     assert((m_pos + size) <= stop);
2252 
2253     if (id != 0x3B) {  // CuePoint ID
2254       m_pos += size;  // consume payload
2255       assert(m_pos <= stop);
2256 
2257       continue;
2258     }
2259 
2260     assert(m_preload_count > 0);
2261 
2262     CuePoint* const pCP = m_cue_points[m_count];
2263     assert(pCP);
2264     assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos));
2265     if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos))
2266       return false;
2267 
2268     pCP->Load(pReader);
2269     ++m_count;
2270     --m_preload_count;
2271 
2272     m_pos += size;  // consume payload
2273     assert(m_pos <= stop);
2274 
2275     return true;  // yes, we loaded a cue point
2276   }
2277 
2278   // return (m_pos < stop);
2279   return false;  // no, we did not load a cue point
2280 }
2281 
Find(long long time_ns,const Track * pTrack,const CuePoint * & pCP,const CuePoint::TrackPosition * & pTP) const2282 bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
2283                 const CuePoint::TrackPosition*& pTP) const {
2284   assert(time_ns >= 0);
2285   assert(pTrack);
2286 
2287 #if 0
2288     LoadCuePoint();  //establish invariant
2289 
2290     assert(m_cue_points);
2291     assert(m_count > 0);
2292 
2293     CuePoint** const ii = m_cue_points;
2294     CuePoint** i = ii;
2295 
2296     CuePoint** const jj = ii + m_count + m_preload_count;
2297     CuePoint** j = jj;
2298 
2299     pCP = *i;
2300     assert(pCP);
2301 
2302     if (time_ns <= pCP->GetTime(m_pSegment))
2303     {
2304         pTP = pCP->Find(pTrack);
2305         return (pTP != NULL);
2306     }
2307 
2308     IMkvReader* const pReader = m_pSegment->m_pReader;
2309 
2310     while (i < j)
2311     {
2312         //INVARIANT:
2313         //[ii, i) <= time_ns
2314         //[i, j)  ?
2315         //[j, jj) > time_ns
2316 
2317         CuePoint** const k = i + (j - i) / 2;
2318         assert(k < jj);
2319 
2320         CuePoint* const pCP = *k;
2321         assert(pCP);
2322 
2323         pCP->Load(pReader);
2324 
2325         const long long t = pCP->GetTime(m_pSegment);
2326 
2327         if (t <= time_ns)
2328             i = k + 1;
2329         else
2330             j = k;
2331 
2332         assert(i <= j);
2333     }
2334 
2335     assert(i == j);
2336     assert(i <= jj);
2337     assert(i > ii);
2338 
2339     pCP = *--i;
2340     assert(pCP);
2341     assert(pCP->GetTime(m_pSegment) <= time_ns);
2342 #else
2343   if (m_cue_points == NULL)
2344     return false;
2345 
2346   if (m_count == 0)
2347     return false;
2348 
2349   CuePoint** const ii = m_cue_points;
2350   CuePoint** i = ii;
2351 
2352   CuePoint** const jj = ii + m_count;
2353   CuePoint** j = jj;
2354 
2355   pCP = *i;
2356   assert(pCP);
2357 
2358   if (time_ns <= pCP->GetTime(m_pSegment)) {
2359     pTP = pCP->Find(pTrack);
2360     return (pTP != NULL);
2361   }
2362 
2363   while (i < j) {
2364     // INVARIANT:
2365     //[ii, i) <= time_ns
2366     //[i, j)  ?
2367     //[j, jj) > time_ns
2368 
2369     CuePoint** const k = i + (j - i) / 2;
2370     assert(k < jj);
2371 
2372     CuePoint* const pCP = *k;
2373     assert(pCP);
2374 
2375     const long long t = pCP->GetTime(m_pSegment);
2376 
2377     if (t <= time_ns)
2378       i = k + 1;
2379     else
2380       j = k;
2381 
2382     assert(i <= j);
2383   }
2384 
2385   assert(i == j);
2386   assert(i <= jj);
2387   assert(i > ii);
2388 
2389   pCP = *--i;
2390   assert(pCP);
2391   assert(pCP->GetTime(m_pSegment) <= time_ns);
2392 #endif
2393 
2394   // TODO: here and elsewhere, it's probably not correct to search
2395   // for the cue point with this time, and then search for a matching
2396   // track.  In principle, the matching track could be on some earlier
2397   // cue point, and with our current algorithm, we'd miss it.  To make
2398   // this bullet-proof, we'd need to create a secondary structure,
2399   // with a list of cue points that apply to a track, and then search
2400   // that track-based structure for a matching cue point.
2401 
2402   pTP = pCP->Find(pTrack);
2403   return (pTP != NULL);
2404 }
2405 
2406 #if 0
2407 bool Cues::FindNext(
2408     long long time_ns,
2409     const Track* pTrack,
2410     const CuePoint*& pCP,
2411     const CuePoint::TrackPosition*& pTP) const
2412 {
2413     pCP = 0;
2414     pTP = 0;
2415 
2416     if (m_count == 0)
2417         return false;
2418 
2419     assert(m_cue_points);
2420 
2421     const CuePoint* const* const ii = m_cue_points;
2422     const CuePoint* const* i = ii;
2423 
2424     const CuePoint* const* const jj = ii + m_count;
2425     const CuePoint* const* j = jj;
2426 
2427     while (i < j)
2428     {
2429         //INVARIANT:
2430         //[ii, i) <= time_ns
2431         //[i, j)  ?
2432         //[j, jj) > time_ns
2433 
2434         const CuePoint* const* const k = i + (j - i) / 2;
2435         assert(k < jj);
2436 
2437         pCP = *k;
2438         assert(pCP);
2439 
2440         const long long t = pCP->GetTime(m_pSegment);
2441 
2442         if (t <= time_ns)
2443             i = k + 1;
2444         else
2445             j = k;
2446 
2447         assert(i <= j);
2448     }
2449 
2450     assert(i == j);
2451     assert(i <= jj);
2452 
2453     if (i >= jj)  //time_ns is greater than max cue point
2454         return false;
2455 
2456     pCP = *i;
2457     assert(pCP);
2458     assert(pCP->GetTime(m_pSegment) > time_ns);
2459 
2460     pTP = pCP->Find(pTrack);
2461     return (pTP != NULL);
2462 }
2463 #endif
2464 
GetFirst() const2465 const CuePoint* Cues::GetFirst() const {
2466   if (m_cue_points == NULL)
2467     return NULL;
2468 
2469   if (m_count == 0)
2470     return NULL;
2471 
2472 #if 0
2473     LoadCuePoint();  //init cues
2474 
2475     const size_t count = m_count + m_preload_count;
2476 
2477     if (count == 0)  //weird
2478         return NULL;
2479 #endif
2480 
2481   CuePoint* const* const pp = m_cue_points;
2482   assert(pp);
2483 
2484   CuePoint* const pCP = pp[0];
2485   assert(pCP);
2486   assert(pCP->GetTimeCode() >= 0);
2487 
2488   return pCP;
2489 }
2490 
GetLast() const2491 const CuePoint* Cues::GetLast() const {
2492   if (m_cue_points == NULL)
2493     return NULL;
2494 
2495   if (m_count <= 0)
2496     return NULL;
2497 
2498 #if 0
2499     LoadCuePoint();  //init cues
2500 
2501     const size_t count = m_count + m_preload_count;
2502 
2503     if (count == 0)  //weird
2504         return NULL;
2505 
2506     const size_t index = count - 1;
2507 
2508     CuePoint* const* const pp = m_cue_points;
2509     assert(pp);
2510 
2511     CuePoint* const pCP = pp[index];
2512     assert(pCP);
2513 
2514     pCP->Load(m_pSegment->m_pReader);
2515     assert(pCP->GetTimeCode() >= 0);
2516 #else
2517   const long index = m_count - 1;
2518 
2519   CuePoint* const* const pp = m_cue_points;
2520   assert(pp);
2521 
2522   CuePoint* const pCP = pp[index];
2523   assert(pCP);
2524   assert(pCP->GetTimeCode() >= 0);
2525 #endif
2526 
2527   return pCP;
2528 }
2529 
GetNext(const CuePoint * pCurr) const2530 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
2531   if (pCurr == NULL)
2532     return NULL;
2533 
2534   assert(pCurr->GetTimeCode() >= 0);
2535   assert(m_cue_points);
2536   assert(m_count >= 1);
2537 
2538 #if 0
2539     const size_t count = m_count + m_preload_count;
2540 
2541     size_t index = pCurr->m_index;
2542     assert(index < count);
2543 
2544     CuePoint* const* const pp = m_cue_points;
2545     assert(pp);
2546     assert(pp[index] == pCurr);
2547 
2548     ++index;
2549 
2550     if (index >= count)
2551         return NULL;
2552 
2553     CuePoint* const pNext = pp[index];
2554     assert(pNext);
2555 
2556     pNext->Load(m_pSegment->m_pReader);
2557 #else
2558   long index = pCurr->m_index;
2559   assert(index < m_count);
2560 
2561   CuePoint* const* const pp = m_cue_points;
2562   assert(pp);
2563   assert(pp[index] == pCurr);
2564 
2565   ++index;
2566 
2567   if (index >= m_count)
2568     return NULL;
2569 
2570   CuePoint* const pNext = pp[index];
2571   assert(pNext);
2572   assert(pNext->GetTimeCode() >= 0);
2573 #endif
2574 
2575   return pNext;
2576 }
2577 
GetBlock(const CuePoint * pCP,const CuePoint::TrackPosition * pTP) const2578 const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
2579                                  const CuePoint::TrackPosition* pTP) const {
2580   if (pCP == NULL)
2581     return NULL;
2582 
2583   if (pTP == NULL)
2584     return NULL;
2585 
2586   return m_pSegment->GetBlock(*pCP, *pTP);
2587 }
2588 
GetBlock(const CuePoint & cp,const CuePoint::TrackPosition & tp)2589 const BlockEntry* Segment::GetBlock(const CuePoint& cp,
2590                                     const CuePoint::TrackPosition& tp) {
2591   Cluster** const ii = m_clusters;
2592   Cluster** i = ii;
2593 
2594   const long count = m_clusterCount + m_clusterPreloadCount;
2595 
2596   Cluster** const jj = ii + count;
2597   Cluster** j = jj;
2598 
2599   while (i < j) {
2600     // INVARIANT:
2601     //[ii, i) < pTP->m_pos
2602     //[i, j) ?
2603     //[j, jj)  > pTP->m_pos
2604 
2605     Cluster** const k = i + (j - i) / 2;
2606     assert(k < jj);
2607 
2608     Cluster* const pCluster = *k;
2609     assert(pCluster);
2610 
2611     // const long long pos_ = pCluster->m_pos;
2612     // assert(pos_);
2613     // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2614 
2615     const long long pos = pCluster->GetPosition();
2616     assert(pos >= 0);
2617 
2618     if (pos < tp.m_pos)
2619       i = k + 1;
2620     else if (pos > tp.m_pos)
2621       j = k;
2622     else
2623       return pCluster->GetEntry(cp, tp);
2624   }
2625 
2626   assert(i == j);
2627   // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2628 
2629   Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos);  //, -1);
2630   assert(pCluster);
2631 
2632   const ptrdiff_t idx = i - m_clusters;
2633 
2634   PreloadCluster(pCluster, idx);
2635   assert(m_clusters);
2636   assert(m_clusterPreloadCount > 0);
2637   assert(m_clusters[idx] == pCluster);
2638 
2639   return pCluster->GetEntry(cp, tp);
2640 }
2641 
FindOrPreloadCluster(long long requested_pos)2642 const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
2643   if (requested_pos < 0)
2644     return 0;
2645 
2646   Cluster** const ii = m_clusters;
2647   Cluster** i = ii;
2648 
2649   const long count = m_clusterCount + m_clusterPreloadCount;
2650 
2651   Cluster** const jj = ii + count;
2652   Cluster** j = jj;
2653 
2654   while (i < j) {
2655     // INVARIANT:
2656     //[ii, i) < pTP->m_pos
2657     //[i, j) ?
2658     //[j, jj)  > pTP->m_pos
2659 
2660     Cluster** const k = i + (j - i) / 2;
2661     assert(k < jj);
2662 
2663     Cluster* const pCluster = *k;
2664     assert(pCluster);
2665 
2666     // const long long pos_ = pCluster->m_pos;
2667     // assert(pos_);
2668     // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2669 
2670     const long long pos = pCluster->GetPosition();
2671     assert(pos >= 0);
2672 
2673     if (pos < requested_pos)
2674       i = k + 1;
2675     else if (pos > requested_pos)
2676       j = k;
2677     else
2678       return pCluster;
2679   }
2680 
2681   assert(i == j);
2682   // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2683 
2684   Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
2685   //-1);
2686   assert(pCluster);
2687 
2688   const ptrdiff_t idx = i - m_clusters;
2689 
2690   PreloadCluster(pCluster, idx);
2691   assert(m_clusters);
2692   assert(m_clusterPreloadCount > 0);
2693   assert(m_clusters[idx] == pCluster);
2694 
2695   return pCluster;
2696 }
2697 
CuePoint(long idx,long long pos)2698 CuePoint::CuePoint(long idx, long long pos)
2699     : m_element_start(0),
2700       m_element_size(0),
2701       m_index(idx),
2702       m_timecode(-1 * pos),
2703       m_track_positions(NULL),
2704       m_track_positions_count(0) {
2705   assert(pos > 0);
2706 }
2707 
~CuePoint()2708 CuePoint::~CuePoint() { delete[] m_track_positions; }
2709 
Load(IMkvReader * pReader)2710 void CuePoint::Load(IMkvReader* pReader) {
2711   // odbgstream os;
2712   // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
2713 
2714   if (m_timecode >= 0)  // already loaded
2715     return;
2716 
2717   assert(m_track_positions == NULL);
2718   assert(m_track_positions_count == 0);
2719 
2720   long long pos_ = -m_timecode;
2721   const long long element_start = pos_;
2722 
2723   long long stop;
2724 
2725   {
2726     long len;
2727 
2728     const long long id = ReadUInt(pReader, pos_, len);
2729     assert(id == 0x3B);  // CuePoint ID
2730     if (id != 0x3B)
2731       return;
2732 
2733     pos_ += len;  // consume ID
2734 
2735     const long long size = ReadUInt(pReader, pos_, len);
2736     assert(size >= 0);
2737 
2738     pos_ += len;  // consume Size field
2739     // pos_ now points to start of payload
2740 
2741     stop = pos_ + size;
2742   }
2743 
2744   const long long element_size = stop - element_start;
2745 
2746   long long pos = pos_;
2747 
2748   // First count number of track positions
2749 
2750   while (pos < stop) {
2751     long len;
2752 
2753     const long long id = ReadUInt(pReader, pos, len);
2754     assert(id >= 0);  // TODO
2755     assert((pos + len) <= stop);
2756 
2757     pos += len;  // consume ID
2758 
2759     const long long size = ReadUInt(pReader, pos, len);
2760     assert(size >= 0);
2761     assert((pos + len) <= stop);
2762 
2763     pos += len;  // consume Size field
2764     assert((pos + size) <= stop);
2765 
2766     if (id == 0x33)  // CueTime ID
2767       m_timecode = UnserializeUInt(pReader, pos, size);
2768 
2769     else if (id == 0x37)  // CueTrackPosition(s) ID
2770       ++m_track_positions_count;
2771 
2772     pos += size;  // consume payload
2773     assert(pos <= stop);
2774   }
2775 
2776   assert(m_timecode >= 0);
2777   assert(m_track_positions_count > 0);
2778 
2779   // os << "CuePoint::Load(cont'd): idpos=" << idpos
2780   //   << " timecode=" << m_timecode
2781   //   << endl;
2782 
2783   m_track_positions = new TrackPosition[m_track_positions_count];
2784 
2785   // Now parse track positions
2786 
2787   TrackPosition* p = m_track_positions;
2788   pos = pos_;
2789 
2790   while (pos < stop) {
2791     long len;
2792 
2793     const long long id = ReadUInt(pReader, pos, len);
2794     assert(id >= 0);  // TODO
2795     assert((pos + len) <= stop);
2796 
2797     pos += len;  // consume ID
2798 
2799     const long long size = ReadUInt(pReader, pos, len);
2800     assert(size >= 0);
2801     assert((pos + len) <= stop);
2802 
2803     pos += len;  // consume Size field
2804     assert((pos + size) <= stop);
2805 
2806     if (id == 0x37) {  // CueTrackPosition(s) ID
2807       TrackPosition& tp = *p++;
2808       tp.Parse(pReader, pos, size);
2809     }
2810 
2811     pos += size;  // consume payload
2812     assert(pos <= stop);
2813   }
2814 
2815   assert(size_t(p - m_track_positions) == m_track_positions_count);
2816 
2817   m_element_start = element_start;
2818   m_element_size = element_size;
2819 }
2820 
Parse(IMkvReader * pReader,long long start_,long long size_)2821 void CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
2822                                     long long size_) {
2823   const long long stop = start_ + size_;
2824   long long pos = start_;
2825 
2826   m_track = -1;
2827   m_pos = -1;
2828   m_block = 1;  // default
2829 
2830   while (pos < stop) {
2831     long len;
2832 
2833     const long long id = ReadUInt(pReader, pos, len);
2834     assert(id >= 0);  // TODO
2835     assert((pos + len) <= stop);
2836 
2837     pos += len;  // consume ID
2838 
2839     const long long size = ReadUInt(pReader, pos, len);
2840     assert(size >= 0);
2841     assert((pos + len) <= stop);
2842 
2843     pos += len;  // consume Size field
2844     assert((pos + size) <= stop);
2845 
2846     if (id == 0x77)  // CueTrack ID
2847       m_track = UnserializeUInt(pReader, pos, size);
2848 
2849     else if (id == 0x71)  // CueClusterPos ID
2850       m_pos = UnserializeUInt(pReader, pos, size);
2851 
2852     else if (id == 0x1378)  // CueBlockNumber
2853       m_block = UnserializeUInt(pReader, pos, size);
2854 
2855     pos += size;  // consume payload
2856     assert(pos <= stop);
2857   }
2858 
2859   assert(m_pos >= 0);
2860   assert(m_track > 0);
2861   // assert(m_block > 0);
2862 }
2863 
Find(const Track * pTrack) const2864 const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
2865   assert(pTrack);
2866 
2867   const long long n = pTrack->GetNumber();
2868 
2869   const TrackPosition* i = m_track_positions;
2870   const TrackPosition* const j = i + m_track_positions_count;
2871 
2872   while (i != j) {
2873     const TrackPosition& p = *i++;
2874 
2875     if (p.m_track == n)
2876       return &p;
2877   }
2878 
2879   return NULL;  // no matching track number found
2880 }
2881 
GetTimeCode() const2882 long long CuePoint::GetTimeCode() const { return m_timecode; }
2883 
GetTime(const Segment * pSegment) const2884 long long CuePoint::GetTime(const Segment* pSegment) const {
2885   assert(pSegment);
2886   assert(m_timecode >= 0);
2887 
2888   const SegmentInfo* const pInfo = pSegment->GetInfo();
2889   assert(pInfo);
2890 
2891   const long long scale = pInfo->GetTimeCodeScale();
2892   assert(scale >= 1);
2893 
2894   const long long time = scale * m_timecode;
2895 
2896   return time;
2897 }
2898 
2899 #if 0
2900 long long Segment::Unparsed() const
2901 {
2902     if (m_size < 0)
2903         return LLONG_MAX;
2904 
2905     const long long stop = m_start + m_size;
2906 
2907     const long long result = stop - m_pos;
2908     assert(result >= 0);
2909 
2910     return result;
2911 }
2912 #else
DoneParsing() const2913 bool Segment::DoneParsing() const {
2914   if (m_size < 0) {
2915     long long total, avail;
2916 
2917     const int status = m_pReader->Length(&total, &avail);
2918 
2919     if (status < 0)  // error
2920       return true;  // must assume done
2921 
2922     if (total < 0)
2923       return false;  // assume live stream
2924 
2925     return (m_pos >= total);
2926   }
2927 
2928   const long long stop = m_start + m_size;
2929 
2930   return (m_pos >= stop);
2931 }
2932 #endif
2933 
GetFirst() const2934 const Cluster* Segment::GetFirst() const {
2935   if ((m_clusters == NULL) || (m_clusterCount <= 0))
2936     return &m_eos;
2937 
2938   Cluster* const pCluster = m_clusters[0];
2939   assert(pCluster);
2940 
2941   return pCluster;
2942 }
2943 
GetLast() const2944 const Cluster* Segment::GetLast() const {
2945   if ((m_clusters == NULL) || (m_clusterCount <= 0))
2946     return &m_eos;
2947 
2948   const long idx = m_clusterCount - 1;
2949 
2950   Cluster* const pCluster = m_clusters[idx];
2951   assert(pCluster);
2952 
2953   return pCluster;
2954 }
2955 
GetCount() const2956 unsigned long Segment::GetCount() const { return m_clusterCount; }
2957 
GetNext(const Cluster * pCurr)2958 const Cluster* Segment::GetNext(const Cluster* pCurr) {
2959   assert(pCurr);
2960   assert(pCurr != &m_eos);
2961   assert(m_clusters);
2962 
2963   long idx = pCurr->m_index;
2964 
2965   if (idx >= 0) {
2966     assert(m_clusterCount > 0);
2967     assert(idx < m_clusterCount);
2968     assert(pCurr == m_clusters[idx]);
2969 
2970     ++idx;
2971 
2972     if (idx >= m_clusterCount)
2973       return &m_eos;  // caller will LoadCluster as desired
2974 
2975     Cluster* const pNext = m_clusters[idx];
2976     assert(pNext);
2977     assert(pNext->m_index >= 0);
2978     assert(pNext->m_index == idx);
2979 
2980     return pNext;
2981   }
2982 
2983   assert(m_clusterPreloadCount > 0);
2984 
2985   long long pos = pCurr->m_element_start;
2986 
2987   assert(m_size >= 0);  // TODO
2988   const long long stop = m_start + m_size;  // end of segment
2989 
2990   {
2991     long len;
2992 
2993     long long result = GetUIntLength(m_pReader, pos, len);
2994     assert(result == 0);
2995     assert((pos + len) <= stop);  // TODO
2996     if (result != 0)
2997       return NULL;
2998 
2999     const long long id = ReadUInt(m_pReader, pos, len);
3000     assert(id == 0x0F43B675);  // Cluster ID
3001     if (id != 0x0F43B675)
3002       return NULL;
3003 
3004     pos += len;  // consume ID
3005 
3006     // Read Size
3007     result = GetUIntLength(m_pReader, pos, len);
3008     assert(result == 0);  // TODO
3009     assert((pos + len) <= stop);  // TODO
3010 
3011     const long long size = ReadUInt(m_pReader, pos, len);
3012     assert(size > 0);  // TODO
3013     // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
3014 
3015     pos += len;  // consume length of size of element
3016     assert((pos + size) <= stop);  // TODO
3017 
3018     // Pos now points to start of payload
3019 
3020     pos += size;  // consume payload
3021   }
3022 
3023   long long off_next = 0;
3024 
3025   while (pos < stop) {
3026     long len;
3027 
3028     long long result = GetUIntLength(m_pReader, pos, len);
3029     assert(result == 0);
3030     assert((pos + len) <= stop);  // TODO
3031     if (result != 0)
3032       return NULL;
3033 
3034     const long long idpos = pos;  // pos of next (potential) cluster
3035 
3036     const long long id = ReadUInt(m_pReader, idpos, len);
3037     assert(id > 0);  // TODO
3038 
3039     pos += len;  // consume ID
3040 
3041     // Read Size
3042     result = GetUIntLength(m_pReader, pos, len);
3043     assert(result == 0);  // TODO
3044     assert((pos + len) <= stop);  // TODO
3045 
3046     const long long size = ReadUInt(m_pReader, pos, len);
3047     assert(size >= 0);  // TODO
3048 
3049     pos += len;  // consume length of size of element
3050     assert((pos + size) <= stop);  // TODO
3051 
3052     // Pos now points to start of payload
3053 
3054     if (size == 0)  // weird
3055       continue;
3056 
3057     if (id == 0x0F43B675) {  // Cluster ID
3058       const long long off_next_ = idpos - m_start;
3059 
3060       long long pos_;
3061       long len_;
3062 
3063       const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);
3064 
3065       assert(status >= 0);
3066 
3067       if (status > 0) {
3068         off_next = off_next_;
3069         break;
3070       }
3071     }
3072 
3073     pos += size;  // consume payload
3074   }
3075 
3076   if (off_next <= 0)
3077     return 0;
3078 
3079   Cluster** const ii = m_clusters + m_clusterCount;
3080   Cluster** i = ii;
3081 
3082   Cluster** const jj = ii + m_clusterPreloadCount;
3083   Cluster** j = jj;
3084 
3085   while (i < j) {
3086     // INVARIANT:
3087     //[0, i) < pos_next
3088     //[i, j) ?
3089     //[j, jj)  > pos_next
3090 
3091     Cluster** const k = i + (j - i) / 2;
3092     assert(k < jj);
3093 
3094     Cluster* const pNext = *k;
3095     assert(pNext);
3096     assert(pNext->m_index < 0);
3097 
3098     // const long long pos_ = pNext->m_pos;
3099     // assert(pos_);
3100     // pos = pos_ * ((pos_ < 0) ? -1 : 1);
3101 
3102     pos = pNext->GetPosition();
3103 
3104     if (pos < off_next)
3105       i = k + 1;
3106     else if (pos > off_next)
3107       j = k;
3108     else
3109       return pNext;
3110   }
3111 
3112   assert(i == j);
3113 
3114   Cluster* const pNext = Cluster::Create(this, -1, off_next);
3115   assert(pNext);
3116 
3117   const ptrdiff_t idx_next = i - m_clusters;  // insertion position
3118 
3119   PreloadCluster(pNext, idx_next);
3120   assert(m_clusters);
3121   assert(idx_next < m_clusterSize);
3122   assert(m_clusters[idx_next] == pNext);
3123 
3124   return pNext;
3125 }
3126 
ParseNext(const Cluster * pCurr,const Cluster * & pResult,long long & pos,long & len)3127 long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
3128                         long long& pos, long& len) {
3129   assert(pCurr);
3130   assert(!pCurr->EOS());
3131   assert(m_clusters);
3132 
3133   pResult = 0;
3134 
3135   if (pCurr->m_index >= 0) {  // loaded (not merely preloaded)
3136     assert(m_clusters[pCurr->m_index] == pCurr);
3137 
3138     const long next_idx = pCurr->m_index + 1;
3139 
3140     if (next_idx < m_clusterCount) {
3141       pResult = m_clusters[next_idx];
3142       return 0;  // success
3143     }
3144 
3145     // curr cluster is last among loaded
3146 
3147     const long result = LoadCluster(pos, len);
3148 
3149     if (result < 0)  // error or underflow
3150       return result;
3151 
3152     if (result > 0)  // no more clusters
3153     {
3154       // pResult = &m_eos;
3155       return 1;
3156     }
3157 
3158     pResult = GetLast();
3159     return 0;  // success
3160   }
3161 
3162   assert(m_pos > 0);
3163 
3164   long long total, avail;
3165 
3166   long status = m_pReader->Length(&total, &avail);
3167 
3168   if (status < 0)  // error
3169     return status;
3170 
3171   assert((total < 0) || (avail <= total));
3172 
3173   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
3174 
3175   // interrogate curr cluster
3176 
3177   pos = pCurr->m_element_start;
3178 
3179   if (pCurr->m_element_size >= 0)
3180     pos += pCurr->m_element_size;
3181   else {
3182     if ((pos + 1) > avail) {
3183       len = 1;
3184       return E_BUFFER_NOT_FULL;
3185     }
3186 
3187     long long result = GetUIntLength(m_pReader, pos, len);
3188 
3189     if (result < 0)  // error
3190       return static_cast<long>(result);
3191 
3192     if (result > 0)  // weird
3193       return E_BUFFER_NOT_FULL;
3194 
3195     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3196       return E_FILE_FORMAT_INVALID;
3197 
3198     if ((pos + len) > avail)
3199       return E_BUFFER_NOT_FULL;
3200 
3201     const long long id = ReadUInt(m_pReader, pos, len);
3202 
3203     if (id != 0x0F43B675)  // weird: not Cluster ID
3204       return -1;
3205 
3206     pos += len;  // consume ID
3207 
3208     // Read Size
3209 
3210     if ((pos + 1) > avail) {
3211       len = 1;
3212       return E_BUFFER_NOT_FULL;
3213     }
3214 
3215     result = GetUIntLength(m_pReader, pos, len);
3216 
3217     if (result < 0)  // error
3218       return static_cast<long>(result);
3219 
3220     if (result > 0)  // weird
3221       return E_BUFFER_NOT_FULL;
3222 
3223     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3224       return E_FILE_FORMAT_INVALID;
3225 
3226     if ((pos + len) > avail)
3227       return E_BUFFER_NOT_FULL;
3228 
3229     const long long size = ReadUInt(m_pReader, pos, len);
3230 
3231     if (size < 0)  // error
3232       return static_cast<long>(size);
3233 
3234     pos += len;  // consume size field
3235 
3236     const long long unknown_size = (1LL << (7 * len)) - 1;
3237 
3238     if (size == unknown_size)  // TODO: should never happen
3239       return E_FILE_FORMAT_INVALID;  // TODO: resolve this
3240 
3241     // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
3242 
3243     if ((segment_stop >= 0) && ((pos + size) > segment_stop))
3244       return E_FILE_FORMAT_INVALID;
3245 
3246     // Pos now points to start of payload
3247 
3248     pos += size;  // consume payload (that is, the current cluster)
3249     assert((segment_stop < 0) || (pos <= segment_stop));
3250 
3251     // By consuming the payload, we are assuming that the curr
3252     // cluster isn't interesting.  That is, we don't bother checking
3253     // whether the payload of the curr cluster is less than what
3254     // happens to be available (obtained via IMkvReader::Length).
3255     // Presumably the caller has already dispensed with the current
3256     // cluster, and really does want the next cluster.
3257   }
3258 
3259   // pos now points to just beyond the last fully-loaded cluster
3260 
3261   for (;;) {
3262     const long status = DoParseNext(pResult, pos, len);
3263 
3264     if (status <= 1)
3265       return status;
3266   }
3267 }
3268 
DoParseNext(const Cluster * & pResult,long long & pos,long & len)3269 long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
3270   long long total, avail;
3271 
3272   long status = m_pReader->Length(&total, &avail);
3273 
3274   if (status < 0)  // error
3275     return status;
3276 
3277   assert((total < 0) || (avail <= total));
3278 
3279   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
3280 
3281   // Parse next cluster.  This is strictly a parsing activity.
3282   // Creation of a new cluster object happens later, after the
3283   // parsing is done.
3284 
3285   long long off_next = 0;
3286   long long cluster_size = -1;
3287 
3288   for (;;) {
3289     if ((total >= 0) && (pos >= total))
3290       return 1;  // EOF
3291 
3292     if ((segment_stop >= 0) && (pos >= segment_stop))
3293       return 1;  // EOF
3294 
3295     if ((pos + 1) > avail) {
3296       len = 1;
3297       return E_BUFFER_NOT_FULL;
3298     }
3299 
3300     long long result = GetUIntLength(m_pReader, pos, len);
3301 
3302     if (result < 0)  // error
3303       return static_cast<long>(result);
3304 
3305     if (result > 0)  // weird
3306       return E_BUFFER_NOT_FULL;
3307 
3308     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3309       return E_FILE_FORMAT_INVALID;
3310 
3311     if ((pos + len) > avail)
3312       return E_BUFFER_NOT_FULL;
3313 
3314     const long long idpos = pos;  // absolute
3315     const long long idoff = pos - m_start;  // relative
3316 
3317     const long long id = ReadUInt(m_pReader, idpos, len);  // absolute
3318 
3319     if (id < 0)  // error
3320       return static_cast<long>(id);
3321 
3322     if (id == 0)  // weird
3323       return -1;  // generic error
3324 
3325     pos += len;  // consume ID
3326 
3327     // Read Size
3328 
3329     if ((pos + 1) > avail) {
3330       len = 1;
3331       return E_BUFFER_NOT_FULL;
3332     }
3333 
3334     result = GetUIntLength(m_pReader, pos, len);
3335 
3336     if (result < 0)  // error
3337       return static_cast<long>(result);
3338 
3339     if (result > 0)  // weird
3340       return E_BUFFER_NOT_FULL;
3341 
3342     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3343       return E_FILE_FORMAT_INVALID;
3344 
3345     if ((pos + len) > avail)
3346       return E_BUFFER_NOT_FULL;
3347 
3348     const long long size = ReadUInt(m_pReader, pos, len);
3349 
3350     if (size < 0)  // error
3351       return static_cast<long>(size);
3352 
3353     pos += len;  // consume length of size of element
3354 
3355     // Pos now points to start of payload
3356 
3357     if (size == 0)  // weird
3358       continue;
3359 
3360     const long long unknown_size = (1LL << (7 * len)) - 1;
3361 
3362     if ((segment_stop >= 0) && (size != unknown_size) &&
3363         ((pos + size) > segment_stop)) {
3364       return E_FILE_FORMAT_INVALID;
3365     }
3366 
3367     if (id == 0x0C53BB6B) {  // Cues ID
3368       if (size == unknown_size)
3369         return E_FILE_FORMAT_INVALID;
3370 
3371       const long long element_stop = pos + size;
3372 
3373       if ((segment_stop >= 0) && (element_stop > segment_stop))
3374         return E_FILE_FORMAT_INVALID;
3375 
3376       const long long element_start = idpos;
3377       const long long element_size = element_stop - element_start;
3378 
3379       if (m_pCues == NULL) {
3380         m_pCues = new Cues(this, pos, size, element_start, element_size);
3381         assert(m_pCues);  // TODO
3382       }
3383 
3384       pos += size;  // consume payload
3385       assert((segment_stop < 0) || (pos <= segment_stop));
3386 
3387       continue;
3388     }
3389 
3390     if (id != 0x0F43B675) {  // not a Cluster ID
3391       if (size == unknown_size)
3392         return E_FILE_FORMAT_INVALID;
3393 
3394       pos += size;  // consume payload
3395       assert((segment_stop < 0) || (pos <= segment_stop));
3396 
3397       continue;
3398     }
3399 
3400 #if 0  // this is commented-out to support incremental cluster parsing
3401         len = static_cast<long>(size);
3402 
3403         if (element_stop > avail)
3404             return E_BUFFER_NOT_FULL;
3405 #endif
3406 
3407     // We have a cluster.
3408 
3409     off_next = idoff;
3410 
3411     if (size != unknown_size)
3412       cluster_size = size;
3413 
3414     break;
3415   }
3416 
3417   assert(off_next > 0);  // have cluster
3418 
3419   // We have parsed the next cluster.
3420   // We have not created a cluster object yet.  What we need
3421   // to do now is determine whether it has already be preloaded
3422   //(in which case, an object for this cluster has already been
3423   // created), and if not, create a new cluster object.
3424 
3425   Cluster** const ii = m_clusters + m_clusterCount;
3426   Cluster** i = ii;
3427 
3428   Cluster** const jj = ii + m_clusterPreloadCount;
3429   Cluster** j = jj;
3430 
3431   while (i < j) {
3432     // INVARIANT:
3433     //[0, i) < pos_next
3434     //[i, j) ?
3435     //[j, jj)  > pos_next
3436 
3437     Cluster** const k = i + (j - i) / 2;
3438     assert(k < jj);
3439 
3440     const Cluster* const pNext = *k;
3441     assert(pNext);
3442     assert(pNext->m_index < 0);
3443 
3444     pos = pNext->GetPosition();
3445     assert(pos >= 0);
3446 
3447     if (pos < off_next)
3448       i = k + 1;
3449     else if (pos > off_next)
3450       j = k;
3451     else {
3452       pResult = pNext;
3453       return 0;  // success
3454     }
3455   }
3456 
3457   assert(i == j);
3458 
3459   long long pos_;
3460   long len_;
3461 
3462   status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
3463 
3464   if (status < 0) {  // error or underflow
3465     pos = pos_;
3466     len = len_;
3467 
3468     return status;
3469   }
3470 
3471   if (status > 0) {  // means "found at least one block entry"
3472     Cluster* const pNext = Cluster::Create(this,
3473                                            -1,  // preloaded
3474                                            off_next);
3475     // element_size);
3476     assert(pNext);
3477 
3478     const ptrdiff_t idx_next = i - m_clusters;  // insertion position
3479 
3480     PreloadCluster(pNext, idx_next);
3481     assert(m_clusters);
3482     assert(idx_next < m_clusterSize);
3483     assert(m_clusters[idx_next] == pNext);
3484 
3485     pResult = pNext;
3486     return 0;  // success
3487   }
3488 
3489   // status == 0 means "no block entries found"
3490 
3491   if (cluster_size < 0) {  // unknown size
3492     const long long payload_pos = pos;  // absolute pos of cluster payload
3493 
3494     for (;;) {  // determine cluster size
3495       if ((total >= 0) && (pos >= total))
3496         break;
3497 
3498       if ((segment_stop >= 0) && (pos >= segment_stop))
3499         break;  // no more clusters
3500 
3501       // Read ID
3502 
3503       if ((pos + 1) > avail) {
3504         len = 1;
3505         return E_BUFFER_NOT_FULL;
3506       }
3507 
3508       long long result = GetUIntLength(m_pReader, pos, len);
3509 
3510       if (result < 0)  // error
3511         return static_cast<long>(result);
3512 
3513       if (result > 0)  // weird
3514         return E_BUFFER_NOT_FULL;
3515 
3516       if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3517         return E_FILE_FORMAT_INVALID;
3518 
3519       if ((pos + len) > avail)
3520         return E_BUFFER_NOT_FULL;
3521 
3522       const long long idpos = pos;
3523       const long long id = ReadUInt(m_pReader, idpos, len);
3524 
3525       if (id < 0)  // error (or underflow)
3526         return static_cast<long>(id);
3527 
3528       // This is the distinguished set of ID's we use to determine
3529       // that we have exhausted the sub-element's inside the cluster
3530       // whose ID we parsed earlier.
3531 
3532       if (id == 0x0F43B675)  // Cluster ID
3533         break;
3534 
3535       if (id == 0x0C53BB6B)  // Cues ID
3536         break;
3537 
3538       pos += len;  // consume ID (of sub-element)
3539 
3540       // Read Size
3541 
3542       if ((pos + 1) > avail) {
3543         len = 1;
3544         return E_BUFFER_NOT_FULL;
3545       }
3546 
3547       result = GetUIntLength(m_pReader, pos, len);
3548 
3549       if (result < 0)  // error
3550         return static_cast<long>(result);
3551 
3552       if (result > 0)  // weird
3553         return E_BUFFER_NOT_FULL;
3554 
3555       if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3556         return E_FILE_FORMAT_INVALID;
3557 
3558       if ((pos + len) > avail)
3559         return E_BUFFER_NOT_FULL;
3560 
3561       const long long size = ReadUInt(m_pReader, pos, len);
3562 
3563       if (size < 0)  // error
3564         return static_cast<long>(size);
3565 
3566       pos += len;  // consume size field of element
3567 
3568       // pos now points to start of sub-element's payload
3569 
3570       if (size == 0)  // weird
3571         continue;
3572 
3573       const long long unknown_size = (1LL << (7 * len)) - 1;
3574 
3575       if (size == unknown_size)
3576         return E_FILE_FORMAT_INVALID;  // not allowed for sub-elements
3577 
3578       if ((segment_stop >= 0) && ((pos + size) > segment_stop))  // weird
3579         return E_FILE_FORMAT_INVALID;
3580 
3581       pos += size;  // consume payload of sub-element
3582       assert((segment_stop < 0) || (pos <= segment_stop));
3583     }  // determine cluster size
3584 
3585     cluster_size = pos - payload_pos;
3586     assert(cluster_size >= 0);  // TODO: handle cluster_size = 0
3587 
3588     pos = payload_pos;  // reset and re-parse original cluster
3589   }
3590 
3591   pos += cluster_size;  // consume payload
3592   assert((segment_stop < 0) || (pos <= segment_stop));
3593 
3594   return 2;  // try to find a cluster that follows next
3595 }
3596 
FindCluster(long long time_ns) const3597 const Cluster* Segment::FindCluster(long long time_ns) const {
3598   if ((m_clusters == NULL) || (m_clusterCount <= 0))
3599     return &m_eos;
3600 
3601   {
3602     Cluster* const pCluster = m_clusters[0];
3603     assert(pCluster);
3604     assert(pCluster->m_index == 0);
3605 
3606     if (time_ns <= pCluster->GetTime())
3607       return pCluster;
3608   }
3609 
3610   // Binary search of cluster array
3611 
3612   long i = 0;
3613   long j = m_clusterCount;
3614 
3615   while (i < j) {
3616     // INVARIANT:
3617     //[0, i) <= time_ns
3618     //[i, j) ?
3619     //[j, m_clusterCount)  > time_ns
3620 
3621     const long k = i + (j - i) / 2;
3622     assert(k < m_clusterCount);
3623 
3624     Cluster* const pCluster = m_clusters[k];
3625     assert(pCluster);
3626     assert(pCluster->m_index == k);
3627 
3628     const long long t = pCluster->GetTime();
3629 
3630     if (t <= time_ns)
3631       i = k + 1;
3632     else
3633       j = k;
3634 
3635     assert(i <= j);
3636   }
3637 
3638   assert(i == j);
3639   assert(i > 0);
3640   assert(i <= m_clusterCount);
3641 
3642   const long k = i - 1;
3643 
3644   Cluster* const pCluster = m_clusters[k];
3645   assert(pCluster);
3646   assert(pCluster->m_index == k);
3647   assert(pCluster->GetTime() <= time_ns);
3648 
3649   return pCluster;
3650 }
3651 
3652 #if 0
3653 const BlockEntry* Segment::Seek(
3654     long long time_ns,
3655     const Track* pTrack) const
3656 {
3657     assert(pTrack);
3658 
3659     if ((m_clusters == NULL) || (m_clusterCount <= 0))
3660         return pTrack->GetEOS();
3661 
3662     Cluster** const i = m_clusters;
3663     assert(i);
3664 
3665     {
3666         Cluster* const pCluster = *i;
3667         assert(pCluster);
3668         assert(pCluster->m_index == 0);  //m_clusterCount > 0
3669         assert(pCluster->m_pSegment == this);
3670 
3671         if (time_ns <= pCluster->GetTime())
3672             return pCluster->GetEntry(pTrack);
3673     }
3674 
3675     Cluster** const j = i + m_clusterCount;
3676 
3677     if (pTrack->GetType() == 2) {  //audio
3678         //TODO: we could decide to use cues for this, as we do for video.
3679         //But we only use it for video because looking around for a keyframe
3680         //can get expensive.  Audio doesn't require anything special so a
3681         //straight cluster search is good enough (we assume).
3682 
3683         Cluster** lo = i;
3684         Cluster** hi = j;
3685 
3686         while (lo < hi)
3687         {
3688             //INVARIANT:
3689             //[i, lo) <= time_ns
3690             //[lo, hi) ?
3691             //[hi, j)  > time_ns
3692 
3693             Cluster** const mid = lo + (hi - lo) / 2;
3694             assert(mid < hi);
3695 
3696             Cluster* const pCluster = *mid;
3697             assert(pCluster);
3698             assert(pCluster->m_index == long(mid - m_clusters));
3699             assert(pCluster->m_pSegment == this);
3700 
3701             const long long t = pCluster->GetTime();
3702 
3703             if (t <= time_ns)
3704                 lo = mid + 1;
3705             else
3706                 hi = mid;
3707 
3708             assert(lo <= hi);
3709         }
3710 
3711         assert(lo == hi);
3712         assert(lo > i);
3713         assert(lo <= j);
3714 
3715         while (lo > i)
3716         {
3717             Cluster* const pCluster = *--lo;
3718             assert(pCluster);
3719             assert(pCluster->GetTime() <= time_ns);
3720 
3721             const BlockEntry* const pBE = pCluster->GetEntry(pTrack);
3722 
3723             if ((pBE != 0) && !pBE->EOS())
3724                 return pBE;
3725 
3726             //landed on empty cluster (no entries)
3727         }
3728 
3729         return pTrack->GetEOS();  //weird
3730     }
3731 
3732     assert(pTrack->GetType() == 1);  //video
3733 
3734     Cluster** lo = i;
3735     Cluster** hi = j;
3736 
3737     while (lo < hi)
3738     {
3739         //INVARIANT:
3740         //[i, lo) <= time_ns
3741         //[lo, hi) ?
3742         //[hi, j)  > time_ns
3743 
3744         Cluster** const mid = lo + (hi - lo) / 2;
3745         assert(mid < hi);
3746 
3747         Cluster* const pCluster = *mid;
3748         assert(pCluster);
3749 
3750         const long long t = pCluster->GetTime();
3751 
3752         if (t <= time_ns)
3753             lo = mid + 1;
3754         else
3755             hi = mid;
3756 
3757         assert(lo <= hi);
3758     }
3759 
3760     assert(lo == hi);
3761     assert(lo > i);
3762     assert(lo <= j);
3763 
3764     Cluster* pCluster = *--lo;
3765     assert(pCluster);
3766     assert(pCluster->GetTime() <= time_ns);
3767 
3768     {
3769         const BlockEntry* const pBE = pCluster->GetEntry(pTrack, time_ns);
3770 
3771         if ((pBE != 0) && !pBE->EOS())  //found a keyframe
3772             return pBE;
3773     }
3774 
3775     const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack);
3776 
3777     while (lo != i)
3778     {
3779         pCluster = *--lo;
3780         assert(pCluster);
3781         assert(pCluster->GetTime() <= time_ns);
3782 
3783         const BlockEntry* const pBlockEntry = pCluster->GetMaxKey(pVideo);
3784 
3785         if ((pBlockEntry != 0) && !pBlockEntry->EOS())
3786             return pBlockEntry;
3787     }
3788 
3789     //weird: we're on the first cluster, but no keyframe found
3790     //should never happen but we must return something anyway
3791 
3792     return pTrack->GetEOS();
3793 }
3794 #endif
3795 
3796 #if 0
3797 bool Segment::SearchCues(
3798     long long time_ns,
3799     Track* pTrack,
3800     Cluster*& pCluster,
3801     const BlockEntry*& pBlockEntry,
3802     const CuePoint*& pCP,
3803     const CuePoint::TrackPosition*& pTP)
3804 {
3805     if (pTrack->GetType() != 1)  //not video
3806         return false;  //TODO: for now, just handle video stream
3807 
3808     if (m_pCues == NULL)
3809         return false;
3810 
3811     if (!m_pCues->Find(time_ns, pTrack, pCP, pTP))
3812         return false;  //weird
3813 
3814     assert(pCP);
3815     assert(pTP);
3816     assert(pTP->m_track == pTrack->GetNumber());
3817 
3818     //We have the cue point and track position we want,
3819     //so we now need to search for the cluster having
3820     //the indicated position.
3821 
3822     return GetCluster(pCP, pTP, pCluster, pBlockEntry);
3823 }
3824 #endif
3825 
GetTracks() const3826 const Tracks* Segment::GetTracks() const { return m_pTracks; }
3827 
GetInfo() const3828 const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
3829 
GetCues() const3830 const Cues* Segment::GetCues() const { return m_pCues; }
3831 
GetChapters() const3832 const Chapters* Segment::GetChapters() const { return m_pChapters; }
3833 
GetSeekHead() const3834 const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
3835 
GetDuration() const3836 long long Segment::GetDuration() const {
3837   assert(m_pInfo);
3838   return m_pInfo->GetDuration();
3839 }
3840 
Chapters(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)3841 Chapters::Chapters(Segment* pSegment, long long payload_start,
3842                    long long payload_size, long long element_start,
3843                    long long element_size)
3844     : m_pSegment(pSegment),
3845       m_start(payload_start),
3846       m_size(payload_size),
3847       m_element_start(element_start),
3848       m_element_size(element_size),
3849       m_editions(NULL),
3850       m_editions_size(0),
3851       m_editions_count(0) {}
3852 
~Chapters()3853 Chapters::~Chapters() {
3854   while (m_editions_count > 0) {
3855     Edition& e = m_editions[--m_editions_count];
3856     e.Clear();
3857   }
3858 }
3859 
Parse()3860 long Chapters::Parse() {
3861   IMkvReader* const pReader = m_pSegment->m_pReader;
3862 
3863   long long pos = m_start;  // payload start
3864   const long long stop = pos + m_size;  // payload stop
3865 
3866   while (pos < stop) {
3867     long long id, size;
3868 
3869     long status = ParseElementHeader(pReader, pos, stop, id, size);
3870 
3871     if (status < 0)  // error
3872       return status;
3873 
3874     if (size == 0)  // weird
3875       continue;
3876 
3877     if (id == 0x05B9) {  // EditionEntry ID
3878       status = ParseEdition(pos, size);
3879 
3880       if (status < 0)  // error
3881         return status;
3882     }
3883 
3884     pos += size;
3885     assert(pos <= stop);
3886   }
3887 
3888   assert(pos == stop);
3889   return 0;
3890 }
3891 
GetEditionCount() const3892 int Chapters::GetEditionCount() const { return m_editions_count; }
3893 
GetEdition(int idx) const3894 const Chapters::Edition* Chapters::GetEdition(int idx) const {
3895   if (idx < 0)
3896     return NULL;
3897 
3898   if (idx >= m_editions_count)
3899     return NULL;
3900 
3901   return m_editions + idx;
3902 }
3903 
ExpandEditionsArray()3904 bool Chapters::ExpandEditionsArray() {
3905   if (m_editions_size > m_editions_count)
3906     return true;  // nothing else to do
3907 
3908   const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
3909 
3910   Edition* const editions = new (std::nothrow) Edition[size];
3911 
3912   if (editions == NULL)
3913     return false;
3914 
3915   for (int idx = 0; idx < m_editions_count; ++idx) {
3916     m_editions[idx].ShallowCopy(editions[idx]);
3917   }
3918 
3919   delete[] m_editions;
3920   m_editions = editions;
3921 
3922   m_editions_size = size;
3923   return true;
3924 }
3925 
ParseEdition(long long pos,long long size)3926 long Chapters::ParseEdition(long long pos, long long size) {
3927   if (!ExpandEditionsArray())
3928     return -1;
3929 
3930   Edition& e = m_editions[m_editions_count++];
3931   e.Init();
3932 
3933   return e.Parse(m_pSegment->m_pReader, pos, size);
3934 }
3935 
Edition()3936 Chapters::Edition::Edition() {}
3937 
~Edition()3938 Chapters::Edition::~Edition() {}
3939 
GetAtomCount() const3940 int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
3941 
GetAtom(int index) const3942 const Chapters::Atom* Chapters::Edition::GetAtom(int index) const {
3943   if (index < 0)
3944     return NULL;
3945 
3946   if (index >= m_atoms_count)
3947     return NULL;
3948 
3949   return m_atoms + index;
3950 }
3951 
Init()3952 void Chapters::Edition::Init() {
3953   m_atoms = NULL;
3954   m_atoms_size = 0;
3955   m_atoms_count = 0;
3956 }
3957 
ShallowCopy(Edition & rhs) const3958 void Chapters::Edition::ShallowCopy(Edition& rhs) const {
3959   rhs.m_atoms = m_atoms;
3960   rhs.m_atoms_size = m_atoms_size;
3961   rhs.m_atoms_count = m_atoms_count;
3962 }
3963 
Clear()3964 void Chapters::Edition::Clear() {
3965   while (m_atoms_count > 0) {
3966     Atom& a = m_atoms[--m_atoms_count];
3967     a.Clear();
3968   }
3969 
3970   delete[] m_atoms;
3971   m_atoms = NULL;
3972 
3973   m_atoms_size = 0;
3974 }
3975 
Parse(IMkvReader * pReader,long long pos,long long size)3976 long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
3977                               long long size) {
3978   const long long stop = pos + size;
3979 
3980   while (pos < stop) {
3981     long long id, size;
3982 
3983     long status = ParseElementHeader(pReader, pos, stop, id, size);
3984 
3985     if (status < 0)  // error
3986       return status;
3987 
3988     if (size == 0)  // weird
3989       continue;
3990 
3991     if (id == 0x36) {  // Atom ID
3992       status = ParseAtom(pReader, pos, size);
3993 
3994       if (status < 0)  // error
3995         return status;
3996     }
3997 
3998     pos += size;
3999     assert(pos <= stop);
4000   }
4001 
4002   assert(pos == stop);
4003   return 0;
4004 }
4005 
ParseAtom(IMkvReader * pReader,long long pos,long long size)4006 long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos,
4007                                   long long size) {
4008   if (!ExpandAtomsArray())
4009     return -1;
4010 
4011   Atom& a = m_atoms[m_atoms_count++];
4012   a.Init();
4013 
4014   return a.Parse(pReader, pos, size);
4015 }
4016 
ExpandAtomsArray()4017 bool Chapters::Edition::ExpandAtomsArray() {
4018   if (m_atoms_size > m_atoms_count)
4019     return true;  // nothing else to do
4020 
4021   const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
4022 
4023   Atom* const atoms = new (std::nothrow) Atom[size];
4024 
4025   if (atoms == NULL)
4026     return false;
4027 
4028   for (int idx = 0; idx < m_atoms_count; ++idx) {
4029     m_atoms[idx].ShallowCopy(atoms[idx]);
4030   }
4031 
4032   delete[] m_atoms;
4033   m_atoms = atoms;
4034 
4035   m_atoms_size = size;
4036   return true;
4037 }
4038 
Atom()4039 Chapters::Atom::Atom() {}
4040 
~Atom()4041 Chapters::Atom::~Atom() {}
4042 
GetUID() const4043 unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
4044 
GetStringUID() const4045 const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
4046 
GetStartTimecode() const4047 long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
4048 
GetStopTimecode() const4049 long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
4050 
GetStartTime(const Chapters * pChapters) const4051 long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
4052   return GetTime(pChapters, m_start_timecode);
4053 }
4054 
GetStopTime(const Chapters * pChapters) const4055 long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
4056   return GetTime(pChapters, m_stop_timecode);
4057 }
4058 
GetDisplayCount() const4059 int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
4060 
GetDisplay(int index) const4061 const Chapters::Display* Chapters::Atom::GetDisplay(int index) const {
4062   if (index < 0)
4063     return NULL;
4064 
4065   if (index >= m_displays_count)
4066     return NULL;
4067 
4068   return m_displays + index;
4069 }
4070 
Init()4071 void Chapters::Atom::Init() {
4072   m_string_uid = NULL;
4073   m_uid = 0;
4074   m_start_timecode = -1;
4075   m_stop_timecode = -1;
4076 
4077   m_displays = NULL;
4078   m_displays_size = 0;
4079   m_displays_count = 0;
4080 }
4081 
ShallowCopy(Atom & rhs) const4082 void Chapters::Atom::ShallowCopy(Atom& rhs) const {
4083   rhs.m_string_uid = m_string_uid;
4084   rhs.m_uid = m_uid;
4085   rhs.m_start_timecode = m_start_timecode;
4086   rhs.m_stop_timecode = m_stop_timecode;
4087 
4088   rhs.m_displays = m_displays;
4089   rhs.m_displays_size = m_displays_size;
4090   rhs.m_displays_count = m_displays_count;
4091 }
4092 
Clear()4093 void Chapters::Atom::Clear() {
4094   delete[] m_string_uid;
4095   m_string_uid = NULL;
4096 
4097   while (m_displays_count > 0) {
4098     Display& d = m_displays[--m_displays_count];
4099     d.Clear();
4100   }
4101 
4102   delete[] m_displays;
4103   m_displays = NULL;
4104 
4105   m_displays_size = 0;
4106 }
4107 
Parse(IMkvReader * pReader,long long pos,long long size)4108 long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
4109   const long long stop = pos + size;
4110 
4111   while (pos < stop) {
4112     long long id, size;
4113 
4114     long status = ParseElementHeader(pReader, pos, stop, id, size);
4115 
4116     if (status < 0)  // error
4117       return status;
4118 
4119     if (size == 0)  // weird
4120       continue;
4121 
4122     if (id == 0x00) {  // Display ID
4123       status = ParseDisplay(pReader, pos, size);
4124 
4125       if (status < 0)  // error
4126         return status;
4127     } else if (id == 0x1654) {  // StringUID ID
4128       status = UnserializeString(pReader, pos, size, m_string_uid);
4129 
4130       if (status < 0)  // error
4131         return status;
4132     } else if (id == 0x33C4) {  // UID ID
4133       long long val;
4134       status = UnserializeInt(pReader, pos, size, val);
4135 
4136       if (status < 0)  // error
4137         return status;
4138 
4139       m_uid = static_cast<unsigned long long>(val);
4140     } else if (id == 0x11) {  // TimeStart ID
4141       const long long val = UnserializeUInt(pReader, pos, size);
4142 
4143       if (val < 0)  // error
4144         return static_cast<long>(val);
4145 
4146       m_start_timecode = val;
4147     } else if (id == 0x12) {  // TimeEnd ID
4148       const long long val = UnserializeUInt(pReader, pos, size);
4149 
4150       if (val < 0)  // error
4151         return static_cast<long>(val);
4152 
4153       m_stop_timecode = val;
4154     }
4155 
4156     pos += size;
4157     assert(pos <= stop);
4158   }
4159 
4160   assert(pos == stop);
4161   return 0;
4162 }
4163 
GetTime(const Chapters * pChapters,long long timecode)4164 long long Chapters::Atom::GetTime(const Chapters* pChapters,
4165                                   long long timecode) {
4166   if (pChapters == NULL)
4167     return -1;
4168 
4169   Segment* const pSegment = pChapters->m_pSegment;
4170 
4171   if (pSegment == NULL)  // weird
4172     return -1;
4173 
4174   const SegmentInfo* const pInfo = pSegment->GetInfo();
4175 
4176   if (pInfo == NULL)
4177     return -1;
4178 
4179   const long long timecode_scale = pInfo->GetTimeCodeScale();
4180 
4181   if (timecode_scale < 1)  // weird
4182     return -1;
4183 
4184   if (timecode < 0)
4185     return -1;
4186 
4187   const long long result = timecode_scale * timecode;
4188 
4189   return result;
4190 }
4191 
ParseDisplay(IMkvReader * pReader,long long pos,long long size)4192 long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos,
4193                                   long long size) {
4194   if (!ExpandDisplaysArray())
4195     return -1;
4196 
4197   Display& d = m_displays[m_displays_count++];
4198   d.Init();
4199 
4200   return d.Parse(pReader, pos, size);
4201 }
4202 
ExpandDisplaysArray()4203 bool Chapters::Atom::ExpandDisplaysArray() {
4204   if (m_displays_size > m_displays_count)
4205     return true;  // nothing else to do
4206 
4207   const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
4208 
4209   Display* const displays = new (std::nothrow) Display[size];
4210 
4211   if (displays == NULL)
4212     return false;
4213 
4214   for (int idx = 0; idx < m_displays_count; ++idx) {
4215     m_displays[idx].ShallowCopy(displays[idx]);
4216   }
4217 
4218   delete[] m_displays;
4219   m_displays = displays;
4220 
4221   m_displays_size = size;
4222   return true;
4223 }
4224 
Display()4225 Chapters::Display::Display() {}
4226 
~Display()4227 Chapters::Display::~Display() {}
4228 
GetString() const4229 const char* Chapters::Display::GetString() const { return m_string; }
4230 
GetLanguage() const4231 const char* Chapters::Display::GetLanguage() const { return m_language; }
4232 
GetCountry() const4233 const char* Chapters::Display::GetCountry() const { return m_country; }
4234 
Init()4235 void Chapters::Display::Init() {
4236   m_string = NULL;
4237   m_language = NULL;
4238   m_country = NULL;
4239 }
4240 
ShallowCopy(Display & rhs) const4241 void Chapters::Display::ShallowCopy(Display& rhs) const {
4242   rhs.m_string = m_string;
4243   rhs.m_language = m_language;
4244   rhs.m_country = m_country;
4245 }
4246 
Clear()4247 void Chapters::Display::Clear() {
4248   delete[] m_string;
4249   m_string = NULL;
4250 
4251   delete[] m_language;
4252   m_language = NULL;
4253 
4254   delete[] m_country;
4255   m_country = NULL;
4256 }
4257 
Parse(IMkvReader * pReader,long long pos,long long size)4258 long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
4259                               long long size) {
4260   const long long stop = pos + size;
4261 
4262   while (pos < stop) {
4263     long long id, size;
4264 
4265     long status = ParseElementHeader(pReader, pos, stop, id, size);
4266 
4267     if (status < 0)  // error
4268       return status;
4269 
4270     if (size == 0)  // weird
4271       continue;
4272 
4273     if (id == 0x05) {  // ChapterString ID
4274       status = UnserializeString(pReader, pos, size, m_string);
4275 
4276       if (status)
4277         return status;
4278     } else if (id == 0x037C) {  // ChapterLanguage ID
4279       status = UnserializeString(pReader, pos, size, m_language);
4280 
4281       if (status)
4282         return status;
4283     } else if (id == 0x037E) {  // ChapterCountry ID
4284       status = UnserializeString(pReader, pos, size, m_country);
4285 
4286       if (status)
4287         return status;
4288     }
4289 
4290     pos += size;
4291     assert(pos <= stop);
4292   }
4293 
4294   assert(pos == stop);
4295   return 0;
4296 }
4297 
SegmentInfo(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)4298 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
4299                          long long element_start, long long element_size)
4300     : m_pSegment(pSegment),
4301       m_start(start),
4302       m_size(size_),
4303       m_element_start(element_start),
4304       m_element_size(element_size),
4305       m_pMuxingAppAsUTF8(NULL),
4306       m_pWritingAppAsUTF8(NULL),
4307       m_pTitleAsUTF8(NULL) {}
4308 
~SegmentInfo()4309 SegmentInfo::~SegmentInfo() {
4310   delete[] m_pMuxingAppAsUTF8;
4311   m_pMuxingAppAsUTF8 = NULL;
4312 
4313   delete[] m_pWritingAppAsUTF8;
4314   m_pWritingAppAsUTF8 = NULL;
4315 
4316   delete[] m_pTitleAsUTF8;
4317   m_pTitleAsUTF8 = NULL;
4318 }
4319 
Parse()4320 long SegmentInfo::Parse() {
4321   assert(m_pMuxingAppAsUTF8 == NULL);
4322   assert(m_pWritingAppAsUTF8 == NULL);
4323   assert(m_pTitleAsUTF8 == NULL);
4324 
4325   IMkvReader* const pReader = m_pSegment->m_pReader;
4326 
4327   long long pos = m_start;
4328   const long long stop = m_start + m_size;
4329 
4330   m_timecodeScale = 1000000;
4331   m_duration = -1;
4332 
4333   while (pos < stop) {
4334     long long id, size;
4335 
4336     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4337 
4338     if (status < 0)  // error
4339       return status;
4340 
4341     if (id == 0x0AD7B1) {  // Timecode Scale
4342       m_timecodeScale = UnserializeUInt(pReader, pos, size);
4343 
4344       if (m_timecodeScale <= 0)
4345         return E_FILE_FORMAT_INVALID;
4346     } else if (id == 0x0489) {  // Segment duration
4347       const long status = UnserializeFloat(pReader, pos, size, m_duration);
4348 
4349       if (status < 0)
4350         return status;
4351 
4352       if (m_duration < 0)
4353         return E_FILE_FORMAT_INVALID;
4354     } else if (id == 0x0D80) {  // MuxingApp
4355       const long status =
4356           UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
4357 
4358       if (status)
4359         return status;
4360     } else if (id == 0x1741) {  // WritingApp
4361       const long status =
4362           UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
4363 
4364       if (status)
4365         return status;
4366     } else if (id == 0x3BA9) {  // Title
4367       const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
4368 
4369       if (status)
4370         return status;
4371     }
4372 
4373     pos += size;
4374     assert(pos <= stop);
4375   }
4376 
4377   assert(pos == stop);
4378 
4379   return 0;
4380 }
4381 
GetTimeCodeScale() const4382 long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
4383 
GetDuration() const4384 long long SegmentInfo::GetDuration() const {
4385   if (m_duration < 0)
4386     return -1;
4387 
4388   assert(m_timecodeScale >= 1);
4389 
4390   const double dd = double(m_duration) * double(m_timecodeScale);
4391   const long long d = static_cast<long long>(dd);
4392 
4393   return d;
4394 }
4395 
GetMuxingAppAsUTF8() const4396 const char* SegmentInfo::GetMuxingAppAsUTF8() const {
4397   return m_pMuxingAppAsUTF8;
4398 }
4399 
GetWritingAppAsUTF8() const4400 const char* SegmentInfo::GetWritingAppAsUTF8() const {
4401   return m_pWritingAppAsUTF8;
4402 }
4403 
GetTitleAsUTF8() const4404 const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
4405 
4406 ///////////////////////////////////////////////////////////////
4407 // ContentEncoding element
ContentCompression()4408 ContentEncoding::ContentCompression::ContentCompression()
4409     : algo(0), settings(NULL), settings_len(0) {}
4410 
~ContentCompression()4411 ContentEncoding::ContentCompression::~ContentCompression() {
4412   delete[] settings;
4413 }
4414 
ContentEncryption()4415 ContentEncoding::ContentEncryption::ContentEncryption()
4416     : algo(0),
4417       key_id(NULL),
4418       key_id_len(0),
4419       signature(NULL),
4420       signature_len(0),
4421       sig_key_id(NULL),
4422       sig_key_id_len(0),
4423       sig_algo(0),
4424       sig_hash_algo(0) {}
4425 
~ContentEncryption()4426 ContentEncoding::ContentEncryption::~ContentEncryption() {
4427   delete[] key_id;
4428   delete[] signature;
4429   delete[] sig_key_id;
4430 }
4431 
ContentEncoding()4432 ContentEncoding::ContentEncoding()
4433     : compression_entries_(NULL),
4434       compression_entries_end_(NULL),
4435       encryption_entries_(NULL),
4436       encryption_entries_end_(NULL),
4437       encoding_order_(0),
4438       encoding_scope_(1),
4439       encoding_type_(0) {}
4440 
~ContentEncoding()4441 ContentEncoding::~ContentEncoding() {
4442   ContentCompression** comp_i = compression_entries_;
4443   ContentCompression** const comp_j = compression_entries_end_;
4444 
4445   while (comp_i != comp_j) {
4446     ContentCompression* const comp = *comp_i++;
4447     delete comp;
4448   }
4449 
4450   delete[] compression_entries_;
4451 
4452   ContentEncryption** enc_i = encryption_entries_;
4453   ContentEncryption** const enc_j = encryption_entries_end_;
4454 
4455   while (enc_i != enc_j) {
4456     ContentEncryption* const enc = *enc_i++;
4457     delete enc;
4458   }
4459 
4460   delete[] encryption_entries_;
4461 }
4462 
4463 const ContentEncoding::ContentCompression*
GetCompressionByIndex(unsigned long idx) const4464 ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
4465   const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4466   assert(count >= 0);
4467 
4468   if (idx >= static_cast<unsigned long>(count))
4469     return NULL;
4470 
4471   return compression_entries_[idx];
4472 }
4473 
GetCompressionCount() const4474 unsigned long ContentEncoding::GetCompressionCount() const {
4475   const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4476   assert(count >= 0);
4477 
4478   return static_cast<unsigned long>(count);
4479 }
4480 
GetEncryptionByIndex(unsigned long idx) const4481 const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex(
4482     unsigned long idx) const {
4483   const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4484   assert(count >= 0);
4485 
4486   if (idx >= static_cast<unsigned long>(count))
4487     return NULL;
4488 
4489   return encryption_entries_[idx];
4490 }
4491 
GetEncryptionCount() const4492 unsigned long ContentEncoding::GetEncryptionCount() const {
4493   const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4494   assert(count >= 0);
4495 
4496   return static_cast<unsigned long>(count);
4497 }
4498 
ParseContentEncAESSettingsEntry(long long start,long long size,IMkvReader * pReader,ContentEncAESSettings * aes)4499 long ContentEncoding::ParseContentEncAESSettingsEntry(
4500     long long start, long long size, IMkvReader* pReader,
4501     ContentEncAESSettings* aes) {
4502   assert(pReader);
4503   assert(aes);
4504 
4505   long long pos = start;
4506   const long long stop = start + size;
4507 
4508   while (pos < stop) {
4509     long long id, size;
4510     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4511     if (status < 0)  // error
4512       return status;
4513 
4514     if (id == 0x7E8) {
4515       // AESSettingsCipherMode
4516       aes->cipher_mode = UnserializeUInt(pReader, pos, size);
4517       if (aes->cipher_mode != 1)
4518         return E_FILE_FORMAT_INVALID;
4519     }
4520 
4521     pos += size;  // consume payload
4522     assert(pos <= stop);
4523   }
4524 
4525   return 0;
4526 }
4527 
ParseContentEncodingEntry(long long start,long long size,IMkvReader * pReader)4528 long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
4529                                                 IMkvReader* pReader) {
4530   assert(pReader);
4531 
4532   long long pos = start;
4533   const long long stop = start + size;
4534 
4535   // Count ContentCompression and ContentEncryption elements.
4536   int compression_count = 0;
4537   int encryption_count = 0;
4538 
4539   while (pos < stop) {
4540     long long id, size;
4541     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4542     if (status < 0)  // error
4543       return status;
4544 
4545     if (id == 0x1034)  // ContentCompression ID
4546       ++compression_count;
4547 
4548     if (id == 0x1035)  // ContentEncryption ID
4549       ++encryption_count;
4550 
4551     pos += size;  // consume payload
4552     assert(pos <= stop);
4553   }
4554 
4555   if (compression_count <= 0 && encryption_count <= 0)
4556     return -1;
4557 
4558   if (compression_count > 0) {
4559     compression_entries_ =
4560         new (std::nothrow) ContentCompression* [compression_count];
4561     if (!compression_entries_)
4562       return -1;
4563     compression_entries_end_ = compression_entries_;
4564   }
4565 
4566   if (encryption_count > 0) {
4567     encryption_entries_ =
4568         new (std::nothrow) ContentEncryption* [encryption_count];
4569     if (!encryption_entries_) {
4570       delete[] compression_entries_;
4571       return -1;
4572     }
4573     encryption_entries_end_ = encryption_entries_;
4574   }
4575 
4576   pos = start;
4577   while (pos < stop) {
4578     long long id, size;
4579     long status = ParseElementHeader(pReader, pos, stop, id, size);
4580     if (status < 0)  // error
4581       return status;
4582 
4583     if (id == 0x1031) {
4584       // ContentEncodingOrder
4585       encoding_order_ = UnserializeUInt(pReader, pos, size);
4586     } else if (id == 0x1032) {
4587       // ContentEncodingScope
4588       encoding_scope_ = UnserializeUInt(pReader, pos, size);
4589       if (encoding_scope_ < 1)
4590         return -1;
4591     } else if (id == 0x1033) {
4592       // ContentEncodingType
4593       encoding_type_ = UnserializeUInt(pReader, pos, size);
4594     } else if (id == 0x1034) {
4595       // ContentCompression ID
4596       ContentCompression* const compression =
4597           new (std::nothrow) ContentCompression();
4598       if (!compression)
4599         return -1;
4600 
4601       status = ParseCompressionEntry(pos, size, pReader, compression);
4602       if (status) {
4603         delete compression;
4604         return status;
4605       }
4606       *compression_entries_end_++ = compression;
4607     } else if (id == 0x1035) {
4608       // ContentEncryption ID
4609       ContentEncryption* const encryption =
4610           new (std::nothrow) ContentEncryption();
4611       if (!encryption)
4612         return -1;
4613 
4614       status = ParseEncryptionEntry(pos, size, pReader, encryption);
4615       if (status) {
4616         delete encryption;
4617         return status;
4618       }
4619       *encryption_entries_end_++ = encryption;
4620     }
4621 
4622     pos += size;  // consume payload
4623     assert(pos <= stop);
4624   }
4625 
4626   assert(pos == stop);
4627   return 0;
4628 }
4629 
ParseCompressionEntry(long long start,long long size,IMkvReader * pReader,ContentCompression * compression)4630 long ContentEncoding::ParseCompressionEntry(long long start, long long size,
4631                                             IMkvReader* pReader,
4632                                             ContentCompression* compression) {
4633   assert(pReader);
4634   assert(compression);
4635 
4636   long long pos = start;
4637   const long long stop = start + size;
4638 
4639   bool valid = false;
4640 
4641   while (pos < stop) {
4642     long long id, size;
4643     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4644     if (status < 0)  // error
4645       return status;
4646 
4647     if (id == 0x254) {
4648       // ContentCompAlgo
4649       long long algo = UnserializeUInt(pReader, pos, size);
4650       if (algo < 0)
4651         return E_FILE_FORMAT_INVALID;
4652       compression->algo = algo;
4653       valid = true;
4654     } else if (id == 0x255) {
4655       // ContentCompSettings
4656       if (size <= 0)
4657         return E_FILE_FORMAT_INVALID;
4658 
4659       const size_t buflen = static_cast<size_t>(size);
4660       typedef unsigned char* buf_t;
4661       const buf_t buf = new (std::nothrow) unsigned char[buflen];
4662       if (buf == NULL)
4663         return -1;
4664 
4665       const int read_status =
4666           pReader->Read(pos, static_cast<long>(buflen), buf);
4667       if (read_status) {
4668         delete[] buf;
4669         return status;
4670       }
4671 
4672       compression->settings = buf;
4673       compression->settings_len = buflen;
4674     }
4675 
4676     pos += size;  // consume payload
4677     assert(pos <= stop);
4678   }
4679 
4680   // ContentCompAlgo is mandatory
4681   if (!valid)
4682     return E_FILE_FORMAT_INVALID;
4683 
4684   return 0;
4685 }
4686 
ParseEncryptionEntry(long long start,long long size,IMkvReader * pReader,ContentEncryption * encryption)4687 long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
4688                                            IMkvReader* pReader,
4689                                            ContentEncryption* encryption) {
4690   assert(pReader);
4691   assert(encryption);
4692 
4693   long long pos = start;
4694   const long long stop = start + size;
4695 
4696   while (pos < stop) {
4697     long long id, size;
4698     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4699     if (status < 0)  // error
4700       return status;
4701 
4702     if (id == 0x7E1) {
4703       // ContentEncAlgo
4704       encryption->algo = UnserializeUInt(pReader, pos, size);
4705       if (encryption->algo != 5)
4706         return E_FILE_FORMAT_INVALID;
4707     } else if (id == 0x7E2) {
4708       // ContentEncKeyID
4709       delete[] encryption -> key_id;
4710       encryption->key_id = NULL;
4711       encryption->key_id_len = 0;
4712 
4713       if (size <= 0)
4714         return E_FILE_FORMAT_INVALID;
4715 
4716       const size_t buflen = static_cast<size_t>(size);
4717       typedef unsigned char* buf_t;
4718       const buf_t buf = new (std::nothrow) unsigned char[buflen];
4719       if (buf == NULL)
4720         return -1;
4721 
4722       const int read_status =
4723           pReader->Read(pos, static_cast<long>(buflen), buf);
4724       if (read_status) {
4725         delete[] buf;
4726         return status;
4727       }
4728 
4729       encryption->key_id = buf;
4730       encryption->key_id_len = buflen;
4731     } else if (id == 0x7E3) {
4732       // ContentSignature
4733       delete[] encryption -> signature;
4734       encryption->signature = NULL;
4735       encryption->signature_len = 0;
4736 
4737       if (size <= 0)
4738         return E_FILE_FORMAT_INVALID;
4739 
4740       const size_t buflen = static_cast<size_t>(size);
4741       typedef unsigned char* buf_t;
4742       const buf_t buf = new (std::nothrow) unsigned char[buflen];
4743       if (buf == NULL)
4744         return -1;
4745 
4746       const int read_status =
4747           pReader->Read(pos, static_cast<long>(buflen), buf);
4748       if (read_status) {
4749         delete[] buf;
4750         return status;
4751       }
4752 
4753       encryption->signature = buf;
4754       encryption->signature_len = buflen;
4755     } else if (id == 0x7E4) {
4756       // ContentSigKeyID
4757       delete[] encryption -> sig_key_id;
4758       encryption->sig_key_id = NULL;
4759       encryption->sig_key_id_len = 0;
4760 
4761       if (size <= 0)
4762         return E_FILE_FORMAT_INVALID;
4763 
4764       const size_t buflen = static_cast<size_t>(size);
4765       typedef unsigned char* buf_t;
4766       const buf_t buf = new (std::nothrow) unsigned char[buflen];
4767       if (buf == NULL)
4768         return -1;
4769 
4770       const int read_status =
4771           pReader->Read(pos, static_cast<long>(buflen), buf);
4772       if (read_status) {
4773         delete[] buf;
4774         return status;
4775       }
4776 
4777       encryption->sig_key_id = buf;
4778       encryption->sig_key_id_len = buflen;
4779     } else if (id == 0x7E5) {
4780       // ContentSigAlgo
4781       encryption->sig_algo = UnserializeUInt(pReader, pos, size);
4782     } else if (id == 0x7E6) {
4783       // ContentSigHashAlgo
4784       encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
4785     } else if (id == 0x7E7) {
4786       // ContentEncAESSettings
4787       const long status = ParseContentEncAESSettingsEntry(
4788           pos, size, pReader, &encryption->aes_settings);
4789       if (status)
4790         return status;
4791     }
4792 
4793     pos += size;  // consume payload
4794     assert(pos <= stop);
4795   }
4796 
4797   return 0;
4798 }
4799 
Track(Segment * pSegment,long long element_start,long long element_size)4800 Track::Track(Segment* pSegment, long long element_start, long long element_size)
4801     : m_pSegment(pSegment),
4802       m_element_start(element_start),
4803       m_element_size(element_size),
4804       content_encoding_entries_(NULL),
4805       content_encoding_entries_end_(NULL) {}
4806 
~Track()4807 Track::~Track() {
4808   Info& info = const_cast<Info&>(m_info);
4809   info.Clear();
4810 
4811   ContentEncoding** i = content_encoding_entries_;
4812   ContentEncoding** const j = content_encoding_entries_end_;
4813 
4814   while (i != j) {
4815     ContentEncoding* const encoding = *i++;
4816     delete encoding;
4817   }
4818 
4819   delete[] content_encoding_entries_;
4820 }
4821 
Create(Segment * pSegment,const Info & info,long long element_start,long long element_size,Track * & pResult)4822 long Track::Create(Segment* pSegment, const Info& info, long long element_start,
4823                    long long element_size, Track*& pResult) {
4824   if (pResult)
4825     return -1;
4826 
4827   Track* const pTrack =
4828       new (std::nothrow) Track(pSegment, element_start, element_size);
4829 
4830   if (pTrack == NULL)
4831     return -1;  // generic error
4832 
4833   const int status = info.Copy(pTrack->m_info);
4834 
4835   if (status) {  // error
4836     delete pTrack;
4837     return status;
4838   }
4839 
4840   pResult = pTrack;
4841   return 0;  // success
4842 }
4843 
Info()4844 Track::Info::Info()
4845     : uid(0),
4846       defaultDuration(0),
4847       codecDelay(0),
4848       seekPreRoll(0),
4849       nameAsUTF8(NULL),
4850       language(NULL),
4851       codecId(NULL),
4852       codecNameAsUTF8(NULL),
4853       codecPrivate(NULL),
4854       codecPrivateSize(0),
4855       lacing(false) {}
4856 
~Info()4857 Track::Info::~Info() { Clear(); }
4858 
Clear()4859 void Track::Info::Clear() {
4860   delete[] nameAsUTF8;
4861   nameAsUTF8 = NULL;
4862 
4863   delete[] language;
4864   language = NULL;
4865 
4866   delete[] codecId;
4867   codecId = NULL;
4868 
4869   delete[] codecPrivate;
4870   codecPrivate = NULL;
4871   codecPrivateSize = 0;
4872 
4873   delete[] codecNameAsUTF8;
4874   codecNameAsUTF8 = NULL;
4875 }
4876 
CopyStr(char * Info::* str,Info & dst_) const4877 int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
4878   if (str == static_cast<char * Info::*>(NULL))
4879     return -1;
4880 
4881   char*& dst = dst_.*str;
4882 
4883   if (dst)  // should be NULL already
4884     return -1;
4885 
4886   const char* const src = this->*str;
4887 
4888   if (src == NULL)
4889     return 0;
4890 
4891   const size_t len = strlen(src);
4892 
4893   dst = new (std::nothrow) char[len + 1];
4894 
4895   if (dst == NULL)
4896     return -1;
4897 
4898   strcpy(dst, src);
4899 
4900   return 0;
4901 }
4902 
Copy(Info & dst) const4903 int Track::Info::Copy(Info& dst) const {
4904   if (&dst == this)
4905     return 0;
4906 
4907   dst.type = type;
4908   dst.number = number;
4909   dst.defaultDuration = defaultDuration;
4910   dst.codecDelay = codecDelay;
4911   dst.seekPreRoll = seekPreRoll;
4912   dst.uid = uid;
4913   dst.lacing = lacing;
4914   dst.settings = settings;
4915 
4916   // We now copy the string member variables from src to dst.
4917   // This involves memory allocation so in principle the operation
4918   // can fail (indeed, that's why we have Info::Copy), so we must
4919   // report this to the caller.  An error return from this function
4920   // therefore implies that the copy was only partially successful.
4921 
4922   if (int status = CopyStr(&Info::nameAsUTF8, dst))
4923     return status;
4924 
4925   if (int status = CopyStr(&Info::language, dst))
4926     return status;
4927 
4928   if (int status = CopyStr(&Info::codecId, dst))
4929     return status;
4930 
4931   if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
4932     return status;
4933 
4934   if (codecPrivateSize > 0) {
4935     if (codecPrivate == NULL)
4936       return -1;
4937 
4938     if (dst.codecPrivate)
4939       return -1;
4940 
4941     if (dst.codecPrivateSize != 0)
4942       return -1;
4943 
4944     dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize];
4945 
4946     if (dst.codecPrivate == NULL)
4947       return -1;
4948 
4949     memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
4950     dst.codecPrivateSize = codecPrivateSize;
4951   }
4952 
4953   return 0;
4954 }
4955 
GetEOS() const4956 const BlockEntry* Track::GetEOS() const { return &m_eos; }
4957 
GetType() const4958 long Track::GetType() const { return m_info.type; }
4959 
GetNumber() const4960 long Track::GetNumber() const { return m_info.number; }
4961 
GetUid() const4962 unsigned long long Track::GetUid() const { return m_info.uid; }
4963 
GetNameAsUTF8() const4964 const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
4965 
GetLanguage() const4966 const char* Track::GetLanguage() const { return m_info.language; }
4967 
GetCodecNameAsUTF8() const4968 const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
4969 
GetCodecId() const4970 const char* Track::GetCodecId() const { return m_info.codecId; }
4971 
GetCodecPrivate(size_t & size) const4972 const unsigned char* Track::GetCodecPrivate(size_t& size) const {
4973   size = m_info.codecPrivateSize;
4974   return m_info.codecPrivate;
4975 }
4976 
GetLacing() const4977 bool Track::GetLacing() const { return m_info.lacing; }
4978 
GetDefaultDuration() const4979 unsigned long long Track::GetDefaultDuration() const {
4980   return m_info.defaultDuration;
4981 }
4982 
GetCodecDelay() const4983 unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
4984 
GetSeekPreRoll() const4985 unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
4986 
GetFirst(const BlockEntry * & pBlockEntry) const4987 long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
4988   const Cluster* pCluster = m_pSegment->GetFirst();
4989 
4990   for (int i = 0;;) {
4991     if (pCluster == NULL) {
4992       pBlockEntry = GetEOS();
4993       return 1;
4994     }
4995 
4996     if (pCluster->EOS()) {
4997 #if 0
4998             if (m_pSegment->Unparsed() <= 0) {  //all clusters have been loaded
4999                 pBlockEntry = GetEOS();
5000                 return 1;
5001             }
5002 #else
5003       if (m_pSegment->DoneParsing()) {
5004         pBlockEntry = GetEOS();
5005         return 1;
5006       }
5007 #endif
5008 
5009       pBlockEntry = 0;
5010       return E_BUFFER_NOT_FULL;
5011     }
5012 
5013     long status = pCluster->GetFirst(pBlockEntry);
5014 
5015     if (status < 0)  // error
5016       return status;
5017 
5018     if (pBlockEntry == 0) {  // empty cluster
5019       pCluster = m_pSegment->GetNext(pCluster);
5020       continue;
5021     }
5022 
5023     for (;;) {
5024       const Block* const pBlock = pBlockEntry->GetBlock();
5025       assert(pBlock);
5026 
5027       const long long tn = pBlock->GetTrackNumber();
5028 
5029       if ((tn == m_info.number) && VetEntry(pBlockEntry))
5030         return 0;
5031 
5032       const BlockEntry* pNextEntry;
5033 
5034       status = pCluster->GetNext(pBlockEntry, pNextEntry);
5035 
5036       if (status < 0)  // error
5037         return status;
5038 
5039       if (pNextEntry == 0)
5040         break;
5041 
5042       pBlockEntry = pNextEntry;
5043     }
5044 
5045     ++i;
5046 
5047     if (i >= 100)
5048       break;
5049 
5050     pCluster = m_pSegment->GetNext(pCluster);
5051   }
5052 
5053   // NOTE: if we get here, it means that we didn't find a block with
5054   // a matching track number.  We interpret that as an error (which
5055   // might be too conservative).
5056 
5057   pBlockEntry = GetEOS();  // so we can return a non-NULL value
5058   return 1;
5059 }
5060 
GetNext(const BlockEntry * pCurrEntry,const BlockEntry * & pNextEntry) const5061 long Track::GetNext(const BlockEntry* pCurrEntry,
5062                     const BlockEntry*& pNextEntry) const {
5063   assert(pCurrEntry);
5064   assert(!pCurrEntry->EOS());  //?
5065 
5066   const Block* const pCurrBlock = pCurrEntry->GetBlock();
5067   assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
5068   if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
5069     return -1;
5070 
5071   const Cluster* pCluster = pCurrEntry->GetCluster();
5072   assert(pCluster);
5073   assert(!pCluster->EOS());
5074 
5075   long status = pCluster->GetNext(pCurrEntry, pNextEntry);
5076 
5077   if (status < 0)  // error
5078     return status;
5079 
5080   for (int i = 0;;) {
5081     while (pNextEntry) {
5082       const Block* const pNextBlock = pNextEntry->GetBlock();
5083       assert(pNextBlock);
5084 
5085       if (pNextBlock->GetTrackNumber() == m_info.number)
5086         return 0;
5087 
5088       pCurrEntry = pNextEntry;
5089 
5090       status = pCluster->GetNext(pCurrEntry, pNextEntry);
5091 
5092       if (status < 0)  // error
5093         return status;
5094     }
5095 
5096     pCluster = m_pSegment->GetNext(pCluster);
5097 
5098     if (pCluster == NULL) {
5099       pNextEntry = GetEOS();
5100       return 1;
5101     }
5102 
5103     if (pCluster->EOS()) {
5104 #if 0
5105             if (m_pSegment->Unparsed() <= 0)   //all clusters have been loaded
5106             {
5107                 pNextEntry = GetEOS();
5108                 return 1;
5109             }
5110 #else
5111       if (m_pSegment->DoneParsing()) {
5112         pNextEntry = GetEOS();
5113         return 1;
5114       }
5115 #endif
5116 
5117       // TODO: there is a potential O(n^2) problem here: we tell the
5118       // caller to (pre)load another cluster, which he does, but then he
5119       // calls GetNext again, which repeats the same search.  This is
5120       // a pathological case, since the only way it can happen is if
5121       // there exists a long sequence of clusters none of which contain a
5122       // block from this track.  One way around this problem is for the
5123       // caller to be smarter when he loads another cluster: don't call
5124       // us back until you have a cluster that contains a block from this
5125       // track. (Of course, that's not cheap either, since our caller
5126       // would have to scan the each cluster as it's loaded, so that
5127       // would just push back the problem.)
5128 
5129       pNextEntry = NULL;
5130       return E_BUFFER_NOT_FULL;
5131     }
5132 
5133     status = pCluster->GetFirst(pNextEntry);
5134 
5135     if (status < 0)  // error
5136       return status;
5137 
5138     if (pNextEntry == NULL)  // empty cluster
5139       continue;
5140 
5141     ++i;
5142 
5143     if (i >= 100)
5144       break;
5145   }
5146 
5147   // NOTE: if we get here, it means that we didn't find a block with
5148   // a matching track number after lots of searching, so we give
5149   // up trying.
5150 
5151   pNextEntry = GetEOS();  // so we can return a non-NULL value
5152   return 1;
5153 }
5154 
VetEntry(const BlockEntry * pBlockEntry) const5155 bool Track::VetEntry(const BlockEntry* pBlockEntry) const {
5156   assert(pBlockEntry);
5157   const Block* const pBlock = pBlockEntry->GetBlock();
5158   assert(pBlock);
5159   assert(pBlock->GetTrackNumber() == m_info.number);
5160   if (!pBlock || pBlock->GetTrackNumber() != m_info.number)
5161     return false;
5162 
5163   // This function is used during a seek to determine whether the
5164   // frame is a valid seek target.  This default function simply
5165   // returns true, which means all frames are valid seek targets.
5166   // It gets overridden by the VideoTrack class, because only video
5167   // keyframes can be used as seek target.
5168 
5169   return true;
5170 }
5171 
Seek(long long time_ns,const BlockEntry * & pResult) const5172 long Track::Seek(long long time_ns, const BlockEntry*& pResult) const {
5173   const long status = GetFirst(pResult);
5174 
5175   if (status < 0)  // buffer underflow, etc
5176     return status;
5177 
5178   assert(pResult);
5179 
5180   if (pResult->EOS())
5181     return 0;
5182 
5183   const Cluster* pCluster = pResult->GetCluster();
5184   assert(pCluster);
5185   assert(pCluster->GetIndex() >= 0);
5186 
5187   if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5188     return 0;
5189 
5190   Cluster** const clusters = m_pSegment->m_clusters;
5191   assert(clusters);
5192 
5193   const long count = m_pSegment->GetCount();  // loaded only, not preloaded
5194   assert(count > 0);
5195 
5196   Cluster** const i = clusters + pCluster->GetIndex();
5197   assert(i);
5198   assert(*i == pCluster);
5199   assert(pCluster->GetTime() <= time_ns);
5200 
5201   Cluster** const j = clusters + count;
5202 
5203   Cluster** lo = i;
5204   Cluster** hi = j;
5205 
5206   while (lo < hi) {
5207     // INVARIANT:
5208     //[i, lo) <= time_ns
5209     //[lo, hi) ?
5210     //[hi, j)  > time_ns
5211 
5212     Cluster** const mid = lo + (hi - lo) / 2;
5213     assert(mid < hi);
5214 
5215     pCluster = *mid;
5216     assert(pCluster);
5217     assert(pCluster->GetIndex() >= 0);
5218     assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5219 
5220     const long long t = pCluster->GetTime();
5221 
5222     if (t <= time_ns)
5223       lo = mid + 1;
5224     else
5225       hi = mid;
5226 
5227     assert(lo <= hi);
5228   }
5229 
5230   assert(lo == hi);
5231   assert(lo > i);
5232   assert(lo <= j);
5233 
5234   while (lo > i) {
5235     pCluster = *--lo;
5236     assert(pCluster);
5237     assert(pCluster->GetTime() <= time_ns);
5238 
5239     pResult = pCluster->GetEntry(this);
5240 
5241     if ((pResult != 0) && !pResult->EOS())
5242       return 0;
5243 
5244     // landed on empty cluster (no entries)
5245   }
5246 
5247   pResult = GetEOS();  // weird
5248   return 0;
5249 }
5250 
GetContentEncodingByIndex(unsigned long idx) const5251 const ContentEncoding* Track::GetContentEncodingByIndex(
5252     unsigned long idx) const {
5253   const ptrdiff_t count =
5254       content_encoding_entries_end_ - content_encoding_entries_;
5255   assert(count >= 0);
5256 
5257   if (idx >= static_cast<unsigned long>(count))
5258     return NULL;
5259 
5260   return content_encoding_entries_[idx];
5261 }
5262 
GetContentEncodingCount() const5263 unsigned long Track::GetContentEncodingCount() const {
5264   const ptrdiff_t count =
5265       content_encoding_entries_end_ - content_encoding_entries_;
5266   assert(count >= 0);
5267 
5268   return static_cast<unsigned long>(count);
5269 }
5270 
ParseContentEncodingsEntry(long long start,long long size)5271 long Track::ParseContentEncodingsEntry(long long start, long long size) {
5272   IMkvReader* const pReader = m_pSegment->m_pReader;
5273   assert(pReader);
5274 
5275   long long pos = start;
5276   const long long stop = start + size;
5277 
5278   // Count ContentEncoding elements.
5279   int count = 0;
5280   while (pos < stop) {
5281     long long id, size;
5282     const long status = ParseElementHeader(pReader, pos, stop, id, size);
5283     if (status < 0)  // error
5284       return status;
5285 
5286     // pos now designates start of element
5287     if (id == 0x2240)  // ContentEncoding ID
5288       ++count;
5289 
5290     pos += size;  // consume payload
5291     assert(pos <= stop);
5292   }
5293 
5294   if (count <= 0)
5295     return -1;
5296 
5297   content_encoding_entries_ = new (std::nothrow) ContentEncoding* [count];
5298   if (!content_encoding_entries_)
5299     return -1;
5300 
5301   content_encoding_entries_end_ = content_encoding_entries_;
5302 
5303   pos = start;
5304   while (pos < stop) {
5305     long long id, size;
5306     long status = ParseElementHeader(pReader, pos, stop, id, size);
5307     if (status < 0)  // error
5308       return status;
5309 
5310     // pos now designates start of element
5311     if (id == 0x2240) {  // ContentEncoding ID
5312       ContentEncoding* const content_encoding =
5313           new (std::nothrow) ContentEncoding();
5314       if (!content_encoding)
5315         return -1;
5316 
5317       status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
5318       if (status) {
5319         delete content_encoding;
5320         return status;
5321       }
5322 
5323       *content_encoding_entries_end_++ = content_encoding;
5324     }
5325 
5326     pos += size;  // consume payload
5327     assert(pos <= stop);
5328   }
5329 
5330   assert(pos == stop);
5331 
5332   return 0;
5333 }
5334 
EOSBlock()5335 Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
5336 
GetKind() const5337 BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
5338 
GetBlock() const5339 const Block* Track::EOSBlock::GetBlock() const { return NULL; }
5340 
VideoTrack(Segment * pSegment,long long element_start,long long element_size)5341 VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
5342                        long long element_size)
5343     : Track(pSegment, element_start, element_size) {}
5344 
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,VideoTrack * & pResult)5345 long VideoTrack::Parse(Segment* pSegment, const Info& info,
5346                        long long element_start, long long element_size,
5347                        VideoTrack*& pResult) {
5348   if (pResult)
5349     return -1;
5350 
5351   if (info.type != Track::kVideo)
5352     return -1;
5353 
5354   long long width = 0;
5355   long long height = 0;
5356   double rate = 0.0;
5357 
5358   IMkvReader* const pReader = pSegment->m_pReader;
5359 
5360   const Settings& s = info.settings;
5361   assert(s.start >= 0);
5362   assert(s.size >= 0);
5363 
5364   long long pos = s.start;
5365   assert(pos >= 0);
5366 
5367   const long long stop = pos + s.size;
5368 
5369   while (pos < stop) {
5370     long long id, size;
5371 
5372     const long status = ParseElementHeader(pReader, pos, stop, id, size);
5373 
5374     if (status < 0)  // error
5375       return status;
5376 
5377     if (id == 0x30) {  // pixel width
5378       width = UnserializeUInt(pReader, pos, size);
5379 
5380       if (width <= 0)
5381         return E_FILE_FORMAT_INVALID;
5382     } else if (id == 0x3A) {  // pixel height
5383       height = UnserializeUInt(pReader, pos, size);
5384 
5385       if (height <= 0)
5386         return E_FILE_FORMAT_INVALID;
5387     } else if (id == 0x0383E3) {  // frame rate
5388       const long status = UnserializeFloat(pReader, pos, size, rate);
5389 
5390       if (status < 0)
5391         return status;
5392 
5393       if (rate <= 0)
5394         return E_FILE_FORMAT_INVALID;
5395     }
5396 
5397     pos += size;  // consume payload
5398     assert(pos <= stop);
5399   }
5400 
5401   assert(pos == stop);
5402 
5403   VideoTrack* const pTrack =
5404       new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
5405 
5406   if (pTrack == NULL)
5407     return -1;  // generic error
5408 
5409   const int status = info.Copy(pTrack->m_info);
5410 
5411   if (status) {  // error
5412     delete pTrack;
5413     return status;
5414   }
5415 
5416   pTrack->m_width = width;
5417   pTrack->m_height = height;
5418   pTrack->m_rate = rate;
5419 
5420   pResult = pTrack;
5421   return 0;  // success
5422 }
5423 
VetEntry(const BlockEntry * pBlockEntry) const5424 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
5425   return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
5426 }
5427 
Seek(long long time_ns,const BlockEntry * & pResult) const5428 long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
5429   const long status = GetFirst(pResult);
5430 
5431   if (status < 0)  // buffer underflow, etc
5432     return status;
5433 
5434   assert(pResult);
5435 
5436   if (pResult->EOS())
5437     return 0;
5438 
5439   const Cluster* pCluster = pResult->GetCluster();
5440   assert(pCluster);
5441   assert(pCluster->GetIndex() >= 0);
5442 
5443   if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5444     return 0;
5445 
5446   Cluster** const clusters = m_pSegment->m_clusters;
5447   assert(clusters);
5448 
5449   const long count = m_pSegment->GetCount();  // loaded only, not pre-loaded
5450   assert(count > 0);
5451 
5452   Cluster** const i = clusters + pCluster->GetIndex();
5453   assert(i);
5454   assert(*i == pCluster);
5455   assert(pCluster->GetTime() <= time_ns);
5456 
5457   Cluster** const j = clusters + count;
5458 
5459   Cluster** lo = i;
5460   Cluster** hi = j;
5461 
5462   while (lo < hi) {
5463     // INVARIANT:
5464     //[i, lo) <= time_ns
5465     //[lo, hi) ?
5466     //[hi, j)  > time_ns
5467 
5468     Cluster** const mid = lo + (hi - lo) / 2;
5469     assert(mid < hi);
5470 
5471     pCluster = *mid;
5472     assert(pCluster);
5473     assert(pCluster->GetIndex() >= 0);
5474     assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5475 
5476     const long long t = pCluster->GetTime();
5477 
5478     if (t <= time_ns)
5479       lo = mid + 1;
5480     else
5481       hi = mid;
5482 
5483     assert(lo <= hi);
5484   }
5485 
5486   assert(lo == hi);
5487   assert(lo > i);
5488   assert(lo <= j);
5489 
5490   pCluster = *--lo;
5491   assert(pCluster);
5492   assert(pCluster->GetTime() <= time_ns);
5493 
5494   pResult = pCluster->GetEntry(this, time_ns);
5495 
5496   if ((pResult != 0) && !pResult->EOS())  // found a keyframe
5497     return 0;
5498 
5499   while (lo != i) {
5500     pCluster = *--lo;
5501     assert(pCluster);
5502     assert(pCluster->GetTime() <= time_ns);
5503 
5504 #if 0
5505         //TODO:
5506         //We need to handle the case when a cluster
5507         //contains multiple keyframes.  Simply returning
5508         //the largest keyframe on the cluster isn't
5509         //good enough.
5510         pResult = pCluster->GetMaxKey(this);
5511 #else
5512     pResult = pCluster->GetEntry(this, time_ns);
5513 #endif
5514 
5515     if ((pResult != 0) && !pResult->EOS())
5516       return 0;
5517   }
5518 
5519   // weird: we're on the first cluster, but no keyframe found
5520   // should never happen but we must return something anyway
5521 
5522   pResult = GetEOS();
5523   return 0;
5524 }
5525 
GetWidth() const5526 long long VideoTrack::GetWidth() const { return m_width; }
5527 
GetHeight() const5528 long long VideoTrack::GetHeight() const { return m_height; }
5529 
GetFrameRate() const5530 double VideoTrack::GetFrameRate() const { return m_rate; }
5531 
AudioTrack(Segment * pSegment,long long element_start,long long element_size)5532 AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
5533                        long long element_size)
5534     : Track(pSegment, element_start, element_size) {}
5535 
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,AudioTrack * & pResult)5536 long AudioTrack::Parse(Segment* pSegment, const Info& info,
5537                        long long element_start, long long element_size,
5538                        AudioTrack*& pResult) {
5539   if (pResult)
5540     return -1;
5541 
5542   if (info.type != Track::kAudio)
5543     return -1;
5544 
5545   IMkvReader* const pReader = pSegment->m_pReader;
5546 
5547   const Settings& s = info.settings;
5548   assert(s.start >= 0);
5549   assert(s.size >= 0);
5550 
5551   long long pos = s.start;
5552   assert(pos >= 0);
5553 
5554   const long long stop = pos + s.size;
5555 
5556   double rate = 8000.0;  // MKV default
5557   long long channels = 1;
5558   long long bit_depth = 0;
5559 
5560   while (pos < stop) {
5561     long long id, size;
5562 
5563     long status = ParseElementHeader(pReader, pos, stop, id, size);
5564 
5565     if (status < 0)  // error
5566       return status;
5567 
5568     if (id == 0x35) {  // Sample Rate
5569       status = UnserializeFloat(pReader, pos, size, rate);
5570 
5571       if (status < 0)
5572         return status;
5573 
5574       if (rate <= 0)
5575         return E_FILE_FORMAT_INVALID;
5576     } else if (id == 0x1F) {  // Channel Count
5577       channels = UnserializeUInt(pReader, pos, size);
5578 
5579       if (channels <= 0)
5580         return E_FILE_FORMAT_INVALID;
5581     } else if (id == 0x2264) {  // Bit Depth
5582       bit_depth = UnserializeUInt(pReader, pos, size);
5583 
5584       if (bit_depth <= 0)
5585         return E_FILE_FORMAT_INVALID;
5586     }
5587 
5588     pos += size;  // consume payload
5589     assert(pos <= stop);
5590   }
5591 
5592   assert(pos == stop);
5593 
5594   AudioTrack* const pTrack =
5595       new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
5596 
5597   if (pTrack == NULL)
5598     return -1;  // generic error
5599 
5600   const int status = info.Copy(pTrack->m_info);
5601 
5602   if (status) {
5603     delete pTrack;
5604     return status;
5605   }
5606 
5607   pTrack->m_rate = rate;
5608   pTrack->m_channels = channels;
5609   pTrack->m_bitDepth = bit_depth;
5610 
5611   pResult = pTrack;
5612   return 0;  // success
5613 }
5614 
GetSamplingRate() const5615 double AudioTrack::GetSamplingRate() const { return m_rate; }
5616 
GetChannels() const5617 long long AudioTrack::GetChannels() const { return m_channels; }
5618 
GetBitDepth() const5619 long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
5620 
Tracks(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)5621 Tracks::Tracks(Segment* pSegment, long long start, long long size_,
5622                long long element_start, long long element_size)
5623     : m_pSegment(pSegment),
5624       m_start(start),
5625       m_size(size_),
5626       m_element_start(element_start),
5627       m_element_size(element_size),
5628       m_trackEntries(NULL),
5629       m_trackEntriesEnd(NULL) {}
5630 
Parse()5631 long Tracks::Parse() {
5632   assert(m_trackEntries == NULL);
5633   assert(m_trackEntriesEnd == NULL);
5634 
5635   const long long stop = m_start + m_size;
5636   IMkvReader* const pReader = m_pSegment->m_pReader;
5637 
5638   int count = 0;
5639   long long pos = m_start;
5640 
5641   while (pos < stop) {
5642     long long id, size;
5643 
5644     const long status = ParseElementHeader(pReader, pos, stop, id, size);
5645 
5646     if (status < 0)  // error
5647       return status;
5648 
5649     if (size == 0)  // weird
5650       continue;
5651 
5652     if (id == 0x2E)  // TrackEntry ID
5653       ++count;
5654 
5655     pos += size;  // consume payload
5656     assert(pos <= stop);
5657   }
5658 
5659   assert(pos == stop);
5660 
5661   if (count <= 0)
5662     return 0;  // success
5663 
5664   m_trackEntries = new (std::nothrow) Track* [count];
5665 
5666   if (m_trackEntries == NULL)
5667     return -1;
5668 
5669   m_trackEntriesEnd = m_trackEntries;
5670 
5671   pos = m_start;
5672 
5673   while (pos < stop) {
5674     const long long element_start = pos;
5675 
5676     long long id, payload_size;
5677 
5678     const long status =
5679         ParseElementHeader(pReader, pos, stop, id, payload_size);
5680 
5681     if (status < 0)  // error
5682       return status;
5683 
5684     if (payload_size == 0)  // weird
5685       continue;
5686 
5687     const long long payload_stop = pos + payload_size;
5688     assert(payload_stop <= stop);  // checked in ParseElement
5689 
5690     const long long element_size = payload_stop - element_start;
5691 
5692     if (id == 0x2E) {  // TrackEntry ID
5693       Track*& pTrack = *m_trackEntriesEnd;
5694       pTrack = NULL;
5695 
5696       const long status = ParseTrackEntry(pos, payload_size, element_start,
5697                                           element_size, pTrack);
5698 
5699       if (status)
5700         return status;
5701 
5702       if (pTrack)
5703         ++m_trackEntriesEnd;
5704     }
5705 
5706     pos = payload_stop;
5707     assert(pos <= stop);
5708   }
5709 
5710   assert(pos == stop);
5711 
5712   return 0;  // success
5713 }
5714 
GetTracksCount() const5715 unsigned long Tracks::GetTracksCount() const {
5716   const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
5717   assert(result >= 0);
5718 
5719   return static_cast<unsigned long>(result);
5720 }
5721 
ParseTrackEntry(long long track_start,long long track_size,long long element_start,long long element_size,Track * & pResult) const5722 long Tracks::ParseTrackEntry(long long track_start, long long track_size,
5723                              long long element_start, long long element_size,
5724                              Track*& pResult) const {
5725   if (pResult)
5726     return -1;
5727 
5728   IMkvReader* const pReader = m_pSegment->m_pReader;
5729 
5730   long long pos = track_start;
5731   const long long track_stop = track_start + track_size;
5732 
5733   Track::Info info;
5734 
5735   info.type = 0;
5736   info.number = 0;
5737   info.uid = 0;
5738   info.defaultDuration = 0;
5739 
5740   Track::Settings v;
5741   v.start = -1;
5742   v.size = -1;
5743 
5744   Track::Settings a;
5745   a.start = -1;
5746   a.size = -1;
5747 
5748   Track::Settings e;  // content_encodings_settings;
5749   e.start = -1;
5750   e.size = -1;
5751 
5752   long long lacing = 1;  // default is true
5753 
5754   while (pos < track_stop) {
5755     long long id, size;
5756 
5757     const long status = ParseElementHeader(pReader, pos, track_stop, id, size);
5758 
5759     if (status < 0)  // error
5760       return status;
5761 
5762     if (size < 0)
5763       return E_FILE_FORMAT_INVALID;
5764 
5765     const long long start = pos;
5766 
5767     if (id == 0x60) {  // VideoSettings ID
5768       v.start = start;
5769       v.size = size;
5770     } else if (id == 0x61) {  // AudioSettings ID
5771       a.start = start;
5772       a.size = size;
5773     } else if (id == 0x2D80) {  // ContentEncodings ID
5774       e.start = start;
5775       e.size = size;
5776     } else if (id == 0x33C5) {  // Track UID
5777       if (size > 8)
5778         return E_FILE_FORMAT_INVALID;
5779 
5780       info.uid = 0;
5781 
5782       long long pos_ = start;
5783       const long long pos_end = start + size;
5784 
5785       while (pos_ != pos_end) {
5786         unsigned char b;
5787 
5788         const int status = pReader->Read(pos_, 1, &b);
5789 
5790         if (status)
5791           return status;
5792 
5793         info.uid <<= 8;
5794         info.uid |= b;
5795 
5796         ++pos_;
5797       }
5798     } else if (id == 0x57) {  // Track Number
5799       const long long num = UnserializeUInt(pReader, pos, size);
5800 
5801       if ((num <= 0) || (num > 127))
5802         return E_FILE_FORMAT_INVALID;
5803 
5804       info.number = static_cast<long>(num);
5805     } else if (id == 0x03) {  // Track Type
5806       const long long type = UnserializeUInt(pReader, pos, size);
5807 
5808       if ((type <= 0) || (type > 254))
5809         return E_FILE_FORMAT_INVALID;
5810 
5811       info.type = static_cast<long>(type);
5812     } else if (id == 0x136E) {  // Track Name
5813       const long status =
5814           UnserializeString(pReader, pos, size, info.nameAsUTF8);
5815 
5816       if (status)
5817         return status;
5818     } else if (id == 0x02B59C) {  // Track Language
5819       const long status = UnserializeString(pReader, pos, size, info.language);
5820 
5821       if (status)
5822         return status;
5823     } else if (id == 0x03E383) {  // Default Duration
5824       const long long duration = UnserializeUInt(pReader, pos, size);
5825 
5826       if (duration < 0)
5827         return E_FILE_FORMAT_INVALID;
5828 
5829       info.defaultDuration = static_cast<unsigned long long>(duration);
5830     } else if (id == 0x06) {  // CodecID
5831       const long status = UnserializeString(pReader, pos, size, info.codecId);
5832 
5833       if (status)
5834         return status;
5835     } else if (id == 0x1C) {  // lacing
5836       lacing = UnserializeUInt(pReader, pos, size);
5837 
5838       if ((lacing < 0) || (lacing > 1))
5839         return E_FILE_FORMAT_INVALID;
5840     } else if (id == 0x23A2) {  // Codec Private
5841       delete[] info.codecPrivate;
5842       info.codecPrivate = NULL;
5843       info.codecPrivateSize = 0;
5844 
5845       const size_t buflen = static_cast<size_t>(size);
5846 
5847       if (buflen) {
5848         typedef unsigned char* buf_t;
5849 
5850         const buf_t buf = new (std::nothrow) unsigned char[buflen];
5851 
5852         if (buf == NULL)
5853           return -1;
5854 
5855         const int status = pReader->Read(pos, static_cast<long>(buflen), buf);
5856 
5857         if (status) {
5858           delete[] buf;
5859           return status;
5860         }
5861 
5862         info.codecPrivate = buf;
5863         info.codecPrivateSize = buflen;
5864       }
5865     } else if (id == 0x058688) {  // Codec Name
5866       const long status =
5867           UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
5868 
5869       if (status)
5870         return status;
5871     } else if (id == 0x16AA) {  // Codec Delay
5872       info.codecDelay = UnserializeUInt(pReader, pos, size);
5873     } else if (id == 0x16BB) {  // Seek Pre Roll
5874       info.seekPreRoll = UnserializeUInt(pReader, pos, size);
5875     }
5876 
5877     pos += size;  // consume payload
5878     assert(pos <= track_stop);
5879   }
5880 
5881   assert(pos == track_stop);
5882 
5883   if (info.number <= 0)  // not specified
5884     return E_FILE_FORMAT_INVALID;
5885 
5886   if (GetTrackByNumber(info.number))
5887     return E_FILE_FORMAT_INVALID;
5888 
5889   if (info.type <= 0)  // not specified
5890     return E_FILE_FORMAT_INVALID;
5891 
5892   info.lacing = (lacing > 0) ? true : false;
5893 
5894   if (info.type == Track::kVideo) {
5895     if (v.start < 0)
5896       return E_FILE_FORMAT_INVALID;
5897 
5898     if (a.start >= 0)
5899       return E_FILE_FORMAT_INVALID;
5900 
5901     info.settings = v;
5902 
5903     VideoTrack* pTrack = NULL;
5904 
5905     const long status = VideoTrack::Parse(m_pSegment, info, element_start,
5906                                           element_size, pTrack);
5907 
5908     if (status)
5909       return status;
5910 
5911     pResult = pTrack;
5912     assert(pResult);
5913 
5914     if (e.start >= 0)
5915       pResult->ParseContentEncodingsEntry(e.start, e.size);
5916   } else if (info.type == Track::kAudio) {
5917     if (a.start < 0)
5918       return E_FILE_FORMAT_INVALID;
5919 
5920     if (v.start >= 0)
5921       return E_FILE_FORMAT_INVALID;
5922 
5923     info.settings = a;
5924 
5925     AudioTrack* pTrack = NULL;
5926 
5927     const long status = AudioTrack::Parse(m_pSegment, info, element_start,
5928                                           element_size, pTrack);
5929 
5930     if (status)
5931       return status;
5932 
5933     pResult = pTrack;
5934     assert(pResult);
5935 
5936     if (e.start >= 0)
5937       pResult->ParseContentEncodingsEntry(e.start, e.size);
5938   } else {
5939     // neither video nor audio - probably metadata or subtitles
5940 
5941     if (a.start >= 0)
5942       return E_FILE_FORMAT_INVALID;
5943 
5944     if (v.start >= 0)
5945       return E_FILE_FORMAT_INVALID;
5946 
5947     if (info.type == Track::kMetadata && e.start >= 0)
5948       return E_FILE_FORMAT_INVALID;
5949 
5950     info.settings.start = -1;
5951     info.settings.size = 0;
5952 
5953     Track* pTrack = NULL;
5954 
5955     const long status =
5956         Track::Create(m_pSegment, info, element_start, element_size, pTrack);
5957 
5958     if (status)
5959       return status;
5960 
5961     pResult = pTrack;
5962     assert(pResult);
5963   }
5964 
5965   return 0;  // success
5966 }
5967 
~Tracks()5968 Tracks::~Tracks() {
5969   Track** i = m_trackEntries;
5970   Track** const j = m_trackEntriesEnd;
5971 
5972   while (i != j) {
5973     Track* const pTrack = *i++;
5974     delete pTrack;
5975   }
5976 
5977   delete[] m_trackEntries;
5978 }
5979 
GetTrackByNumber(long tn) const5980 const Track* Tracks::GetTrackByNumber(long tn) const {
5981   if (tn < 0)
5982     return NULL;
5983 
5984   Track** i = m_trackEntries;
5985   Track** const j = m_trackEntriesEnd;
5986 
5987   while (i != j) {
5988     Track* const pTrack = *i++;
5989 
5990     if (pTrack == NULL)
5991       continue;
5992 
5993     if (tn == pTrack->GetNumber())
5994       return pTrack;
5995   }
5996 
5997   return NULL;  // not found
5998 }
5999 
GetTrackByIndex(unsigned long idx) const6000 const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
6001   const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
6002 
6003   if (idx >= static_cast<unsigned long>(count))
6004     return NULL;
6005 
6006   return m_trackEntries[idx];
6007 }
6008 
6009 #if 0
6010 long long Cluster::Unparsed() const
6011 {
6012     if (m_timecode < 0)  //not even partially loaded
6013         return LLONG_MAX;
6014 
6015     assert(m_pos >= m_element_start);
6016     //assert(m_element_size > m_size);
6017 
6018     const long long element_stop = m_element_start + m_element_size;
6019     assert(m_pos <= element_stop);
6020 
6021     const long long result = element_stop - m_pos;
6022     assert(result >= 0);
6023 
6024     return result;
6025 }
6026 #endif
6027 
Load(long long & pos,long & len) const6028 long Cluster::Load(long long& pos, long& len) const {
6029   assert(m_pSegment);
6030   assert(m_pos >= m_element_start);
6031 
6032   if (m_timecode >= 0)  // at least partially loaded
6033     return 0;
6034 
6035   assert(m_pos == m_element_start);
6036   assert(m_element_size < 0);
6037 
6038   IMkvReader* const pReader = m_pSegment->m_pReader;
6039 
6040   long long total, avail;
6041 
6042   const int status = pReader->Length(&total, &avail);
6043 
6044   if (status < 0)  // error
6045     return status;
6046 
6047   assert((total < 0) || (avail <= total));
6048   assert((total < 0) || (m_pos <= total));  // TODO: verify this
6049 
6050   pos = m_pos;
6051 
6052   long long cluster_size = -1;
6053 
6054   {
6055     if ((pos + 1) > avail) {
6056       len = 1;
6057       return E_BUFFER_NOT_FULL;
6058     }
6059 
6060     long long result = GetUIntLength(pReader, pos, len);
6061 
6062     if (result < 0)  // error or underflow
6063       return static_cast<long>(result);
6064 
6065     if (result > 0)  // underflow (weird)
6066       return E_BUFFER_NOT_FULL;
6067 
6068     // if ((pos + len) > segment_stop)
6069     //    return E_FILE_FORMAT_INVALID;
6070 
6071     if ((pos + len) > avail)
6072       return E_BUFFER_NOT_FULL;
6073 
6074     const long long id_ = ReadUInt(pReader, pos, len);
6075 
6076     if (id_ < 0)  // error
6077       return static_cast<long>(id_);
6078 
6079     if (id_ != 0x0F43B675)  // Cluster ID
6080       return E_FILE_FORMAT_INVALID;
6081 
6082     pos += len;  // consume id
6083 
6084     // read cluster size
6085 
6086     if ((pos + 1) > avail) {
6087       len = 1;
6088       return E_BUFFER_NOT_FULL;
6089     }
6090 
6091     result = GetUIntLength(pReader, pos, len);
6092 
6093     if (result < 0)  // error
6094       return static_cast<long>(result);
6095 
6096     if (result > 0)  // weird
6097       return E_BUFFER_NOT_FULL;
6098 
6099     // if ((pos + len) > segment_stop)
6100     //    return E_FILE_FORMAT_INVALID;
6101 
6102     if ((pos + len) > avail)
6103       return E_BUFFER_NOT_FULL;
6104 
6105     const long long size = ReadUInt(pReader, pos, len);
6106 
6107     if (size < 0)  // error
6108       return static_cast<long>(cluster_size);
6109 
6110     if (size == 0)
6111       return E_FILE_FORMAT_INVALID;  // TODO: verify this
6112 
6113     pos += len;  // consume length of size of element
6114 
6115     const long long unknown_size = (1LL << (7 * len)) - 1;
6116 
6117     if (size != unknown_size)
6118       cluster_size = size;
6119   }
6120 
6121 // pos points to start of payload
6122 
6123 #if 0
6124     len = static_cast<long>(size_);
6125 
6126     if (cluster_stop > avail)
6127         return E_BUFFER_NOT_FULL;
6128 #endif
6129 
6130   long long timecode = -1;
6131   long long new_pos = -1;
6132   bool bBlock = false;
6133 
6134   long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
6135 
6136   for (;;) {
6137     if ((cluster_stop >= 0) && (pos >= cluster_stop))
6138       break;
6139 
6140     // Parse ID
6141 
6142     if ((pos + 1) > avail) {
6143       len = 1;
6144       return E_BUFFER_NOT_FULL;
6145     }
6146 
6147     long long result = GetUIntLength(pReader, pos, len);
6148 
6149     if (result < 0)  // error
6150       return static_cast<long>(result);
6151 
6152     if (result > 0)  // weird
6153       return E_BUFFER_NOT_FULL;
6154 
6155     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6156       return E_FILE_FORMAT_INVALID;
6157 
6158     if ((pos + len) > avail)
6159       return E_BUFFER_NOT_FULL;
6160 
6161     const long long id = ReadUInt(pReader, pos, len);
6162 
6163     if (id < 0)  // error
6164       return static_cast<long>(id);
6165 
6166     if (id == 0)
6167       return E_FILE_FORMAT_INVALID;
6168 
6169     // This is the distinguished set of ID's we use to determine
6170     // that we have exhausted the sub-element's inside the cluster
6171     // whose ID we parsed earlier.
6172 
6173     if (id == 0x0F43B675)  // Cluster ID
6174       break;
6175 
6176     if (id == 0x0C53BB6B)  // Cues ID
6177       break;
6178 
6179     pos += len;  // consume ID field
6180 
6181     // Parse Size
6182 
6183     if ((pos + 1) > avail) {
6184       len = 1;
6185       return E_BUFFER_NOT_FULL;
6186     }
6187 
6188     result = GetUIntLength(pReader, pos, len);
6189 
6190     if (result < 0)  // error
6191       return static_cast<long>(result);
6192 
6193     if (result > 0)  // weird
6194       return E_BUFFER_NOT_FULL;
6195 
6196     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6197       return E_FILE_FORMAT_INVALID;
6198 
6199     if ((pos + len) > avail)
6200       return E_BUFFER_NOT_FULL;
6201 
6202     const long long size = ReadUInt(pReader, pos, len);
6203 
6204     if (size < 0)  // error
6205       return static_cast<long>(size);
6206 
6207     const long long unknown_size = (1LL << (7 * len)) - 1;
6208 
6209     if (size == unknown_size)
6210       return E_FILE_FORMAT_INVALID;
6211 
6212     pos += len;  // consume size field
6213 
6214     if ((cluster_stop >= 0) && (pos > cluster_stop))
6215       return E_FILE_FORMAT_INVALID;
6216 
6217     // pos now points to start of payload
6218 
6219     if (size == 0)  // weird
6220       continue;
6221 
6222     if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
6223       return E_FILE_FORMAT_INVALID;
6224 
6225     if (id == 0x67) {  // TimeCode ID
6226       len = static_cast<long>(size);
6227 
6228       if ((pos + size) > avail)
6229         return E_BUFFER_NOT_FULL;
6230 
6231       timecode = UnserializeUInt(pReader, pos, size);
6232 
6233       if (timecode < 0)  // error (or underflow)
6234         return static_cast<long>(timecode);
6235 
6236       new_pos = pos + size;
6237 
6238       if (bBlock)
6239         break;
6240     } else if (id == 0x20) {  // BlockGroup ID
6241       bBlock = true;
6242       break;
6243     } else if (id == 0x23) {  // SimpleBlock ID
6244       bBlock = true;
6245       break;
6246     }
6247 
6248     pos += size;  // consume payload
6249     assert((cluster_stop < 0) || (pos <= cluster_stop));
6250   }
6251 
6252   assert((cluster_stop < 0) || (pos <= cluster_stop));
6253 
6254   if (timecode < 0)  // no timecode found
6255     return E_FILE_FORMAT_INVALID;
6256 
6257   if (!bBlock)
6258     return E_FILE_FORMAT_INVALID;
6259 
6260   m_pos = new_pos;  // designates position just beyond timecode payload
6261   m_timecode = timecode;  // m_timecode >= 0 means we're partially loaded
6262 
6263   if (cluster_size >= 0)
6264     m_element_size = cluster_stop - m_element_start;
6265 
6266   return 0;
6267 }
6268 
Parse(long long & pos,long & len) const6269 long Cluster::Parse(long long& pos, long& len) const {
6270   long status = Load(pos, len);
6271 
6272   if (status < 0)
6273     return status;
6274 
6275   assert(m_pos >= m_element_start);
6276   assert(m_timecode >= 0);
6277   // assert(m_size > 0);
6278   // assert(m_element_size > m_size);
6279 
6280   const long long cluster_stop =
6281       (m_element_size < 0) ? -1 : m_element_start + m_element_size;
6282 
6283   if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
6284     return 1;  // nothing else to do
6285 
6286   IMkvReader* const pReader = m_pSegment->m_pReader;
6287 
6288   long long total, avail;
6289 
6290   status = pReader->Length(&total, &avail);
6291 
6292   if (status < 0)  // error
6293     return status;
6294 
6295   assert((total < 0) || (avail <= total));
6296 
6297   pos = m_pos;
6298 
6299   for (;;) {
6300     if ((cluster_stop >= 0) && (pos >= cluster_stop))
6301       break;
6302 
6303     if ((total >= 0) && (pos >= total)) {
6304       if (m_element_size < 0)
6305         m_element_size = pos - m_element_start;
6306 
6307       break;
6308     }
6309 
6310     // Parse ID
6311 
6312     if ((pos + 1) > avail) {
6313       len = 1;
6314       return E_BUFFER_NOT_FULL;
6315     }
6316 
6317     long long result = GetUIntLength(pReader, pos, len);
6318 
6319     if (result < 0)  // error
6320       return static_cast<long>(result);
6321 
6322     if (result > 0)  // weird
6323       return E_BUFFER_NOT_FULL;
6324 
6325     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6326       return E_FILE_FORMAT_INVALID;
6327 
6328     if ((pos + len) > avail)
6329       return E_BUFFER_NOT_FULL;
6330 
6331     const long long id = ReadUInt(pReader, pos, len);
6332 
6333     if (id < 0)  // error
6334       return static_cast<long>(id);
6335 
6336     if (id == 0)  // weird
6337       return E_FILE_FORMAT_INVALID;
6338 
6339     // This is the distinguished set of ID's we use to determine
6340     // that we have exhausted the sub-element's inside the cluster
6341     // whose ID we parsed earlier.
6342 
6343     if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) {  // Cluster or Cues ID
6344       if (m_element_size < 0)
6345         m_element_size = pos - m_element_start;
6346 
6347       break;
6348     }
6349 
6350     pos += len;  // consume ID field
6351 
6352     // Parse Size
6353 
6354     if ((pos + 1) > avail) {
6355       len = 1;
6356       return E_BUFFER_NOT_FULL;
6357     }
6358 
6359     result = GetUIntLength(pReader, pos, len);
6360 
6361     if (result < 0)  // error
6362       return static_cast<long>(result);
6363 
6364     if (result > 0)  // weird
6365       return E_BUFFER_NOT_FULL;
6366 
6367     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6368       return E_FILE_FORMAT_INVALID;
6369 
6370     if ((pos + len) > avail)
6371       return E_BUFFER_NOT_FULL;
6372 
6373     const long long size = ReadUInt(pReader, pos, len);
6374 
6375     if (size < 0)  // error
6376       return static_cast<long>(size);
6377 
6378     const long long unknown_size = (1LL << (7 * len)) - 1;
6379 
6380     if (size == unknown_size)
6381       return E_FILE_FORMAT_INVALID;
6382 
6383     pos += len;  // consume size field
6384 
6385     if ((cluster_stop >= 0) && (pos > cluster_stop))
6386       return E_FILE_FORMAT_INVALID;
6387 
6388     // pos now points to start of payload
6389 
6390     if (size == 0)  // weird
6391       continue;
6392 
6393     // const long long block_start = pos;
6394     const long long block_stop = pos + size;
6395 
6396     if (cluster_stop >= 0) {
6397       if (block_stop > cluster_stop) {
6398         if ((id == 0x20) || (id == 0x23))
6399           return E_FILE_FORMAT_INVALID;
6400 
6401         pos = cluster_stop;
6402         break;
6403       }
6404     } else if ((total >= 0) && (block_stop > total)) {
6405       m_element_size = total - m_element_start;
6406       pos = total;
6407       break;
6408     } else if (block_stop > avail) {
6409       len = static_cast<long>(size);
6410       return E_BUFFER_NOT_FULL;
6411     }
6412 
6413     Cluster* const this_ = const_cast<Cluster*>(this);
6414 
6415     if (id == 0x20)  // BlockGroup
6416       return this_->ParseBlockGroup(size, pos, len);
6417 
6418     if (id == 0x23)  // SimpleBlock
6419       return this_->ParseSimpleBlock(size, pos, len);
6420 
6421     pos += size;  // consume payload
6422     assert((cluster_stop < 0) || (pos <= cluster_stop));
6423   }
6424 
6425   assert(m_element_size > 0);
6426 
6427   m_pos = pos;
6428   assert((cluster_stop < 0) || (m_pos <= cluster_stop));
6429 
6430   if (m_entries_count > 0) {
6431     const long idx = m_entries_count - 1;
6432 
6433     const BlockEntry* const pLast = m_entries[idx];
6434     assert(pLast);
6435 
6436     const Block* const pBlock = pLast->GetBlock();
6437     assert(pBlock);
6438 
6439     const long long start = pBlock->m_start;
6440 
6441     if ((total >= 0) && (start > total))
6442       return -1;  // defend against trucated stream
6443 
6444     const long long size = pBlock->m_size;
6445 
6446     const long long stop = start + size;
6447     assert((cluster_stop < 0) || (stop <= cluster_stop));
6448 
6449     if ((total >= 0) && (stop > total))
6450       return -1;  // defend against trucated stream
6451   }
6452 
6453   return 1;  // no more entries
6454 }
6455 
ParseSimpleBlock(long long block_size,long long & pos,long & len)6456 long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
6457                                long& len) {
6458   const long long block_start = pos;
6459   const long long block_stop = pos + block_size;
6460 
6461   IMkvReader* const pReader = m_pSegment->m_pReader;
6462 
6463   long long total, avail;
6464 
6465   long status = pReader->Length(&total, &avail);
6466 
6467   if (status < 0)  // error
6468     return status;
6469 
6470   assert((total < 0) || (avail <= total));
6471 
6472   // parse track number
6473 
6474   if ((pos + 1) > avail) {
6475     len = 1;
6476     return E_BUFFER_NOT_FULL;
6477   }
6478 
6479   long long result = GetUIntLength(pReader, pos, len);
6480 
6481   if (result < 0)  // error
6482     return static_cast<long>(result);
6483 
6484   if (result > 0)  // weird
6485     return E_BUFFER_NOT_FULL;
6486 
6487   if ((pos + len) > block_stop)
6488     return E_FILE_FORMAT_INVALID;
6489 
6490   if ((pos + len) > avail)
6491     return E_BUFFER_NOT_FULL;
6492 
6493   const long long track = ReadUInt(pReader, pos, len);
6494 
6495   if (track < 0)  // error
6496     return static_cast<long>(track);
6497 
6498   if (track == 0)
6499     return E_FILE_FORMAT_INVALID;
6500 
6501 #if 0
6502     //TODO(matthewjheaney)
6503     //This turned out to be too conservative.  The problem is that
6504     //if we see a track header in the tracks element with an unsupported
6505     //track type, we throw that track header away, so it is not present
6506     //in the track map.  But even though we don't understand the track
6507     //header, there are still blocks in the cluster with that track
6508     //number.  It was our decision to ignore that track header, so it's
6509     //up to us to deal with blocks associated with that track -- we
6510     //cannot simply report an error since technically there's nothing
6511     //wrong with the file.
6512     //
6513     //For now we go ahead and finish the parse, creating a block entry
6514     //for this block.  This is somewhat wasteful, because without a
6515     //track header there's nothing you can do with the block. What
6516     //we really need here is a special return value that indicates to
6517     //the caller that he should ignore this particular block, and
6518     //continue parsing.
6519 
6520     const Tracks* const pTracks = m_pSegment->GetTracks();
6521     assert(pTracks);
6522 
6523     const long tn = static_cast<long>(track);
6524 
6525     const Track* const pTrack = pTracks->GetTrackByNumber(tn);
6526 
6527     if (pTrack == NULL)
6528         return E_FILE_FORMAT_INVALID;
6529 #endif
6530 
6531   pos += len;  // consume track number
6532 
6533   if ((pos + 2) > block_stop)
6534     return E_FILE_FORMAT_INVALID;
6535 
6536   if ((pos + 2) > avail) {
6537     len = 2;
6538     return E_BUFFER_NOT_FULL;
6539   }
6540 
6541   pos += 2;  // consume timecode
6542 
6543   if ((pos + 1) > block_stop)
6544     return E_FILE_FORMAT_INVALID;
6545 
6546   if ((pos + 1) > avail) {
6547     len = 1;
6548     return E_BUFFER_NOT_FULL;
6549   }
6550 
6551   unsigned char flags;
6552 
6553   status = pReader->Read(pos, 1, &flags);
6554 
6555   if (status < 0) {  // error or underflow
6556     len = 1;
6557     return status;
6558   }
6559 
6560   ++pos;  // consume flags byte
6561   assert(pos <= avail);
6562 
6563   if (pos >= block_stop)
6564     return E_FILE_FORMAT_INVALID;
6565 
6566   const int lacing = int(flags & 0x06) >> 1;
6567 
6568   if ((lacing != 0) && (block_stop > avail)) {
6569     len = static_cast<long>(block_stop - pos);
6570     return E_BUFFER_NOT_FULL;
6571   }
6572 
6573   status = CreateBlock(0x23,  // simple block id
6574                        block_start, block_size,
6575                        0);  // DiscardPadding
6576 
6577   if (status != 0)
6578     return status;
6579 
6580   m_pos = block_stop;
6581 
6582   return 0;  // success
6583 }
6584 
ParseBlockGroup(long long payload_size,long long & pos,long & len)6585 long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
6586                               long& len) {
6587   const long long payload_start = pos;
6588   const long long payload_stop = pos + payload_size;
6589 
6590   IMkvReader* const pReader = m_pSegment->m_pReader;
6591 
6592   long long total, avail;
6593 
6594   long status = pReader->Length(&total, &avail);
6595 
6596   if (status < 0)  // error
6597     return status;
6598 
6599   assert((total < 0) || (avail <= total));
6600 
6601   if ((total >= 0) && (payload_stop > total))
6602     return E_FILE_FORMAT_INVALID;
6603 
6604   if (payload_stop > avail) {
6605     len = static_cast<long>(payload_size);
6606     return E_BUFFER_NOT_FULL;
6607   }
6608 
6609   long long discard_padding = 0;
6610 
6611   while (pos < payload_stop) {
6612     // parse sub-block element ID
6613 
6614     if ((pos + 1) > avail) {
6615       len = 1;
6616       return E_BUFFER_NOT_FULL;
6617     }
6618 
6619     long long result = GetUIntLength(pReader, pos, len);
6620 
6621     if (result < 0)  // error
6622       return static_cast<long>(result);
6623 
6624     if (result > 0)  // weird
6625       return E_BUFFER_NOT_FULL;
6626 
6627     if ((pos + len) > payload_stop)
6628       return E_FILE_FORMAT_INVALID;
6629 
6630     if ((pos + len) > avail)
6631       return E_BUFFER_NOT_FULL;
6632 
6633     const long long id = ReadUInt(pReader, pos, len);
6634 
6635     if (id < 0)  // error
6636       return static_cast<long>(id);
6637 
6638     if (id == 0)  // not a value ID
6639       return E_FILE_FORMAT_INVALID;
6640 
6641     pos += len;  // consume ID field
6642 
6643     // Parse Size
6644 
6645     if ((pos + 1) > avail) {
6646       len = 1;
6647       return E_BUFFER_NOT_FULL;
6648     }
6649 
6650     result = GetUIntLength(pReader, pos, len);
6651 
6652     if (result < 0)  // error
6653       return static_cast<long>(result);
6654 
6655     if (result > 0)  // weird
6656       return E_BUFFER_NOT_FULL;
6657 
6658     if ((pos + len) > payload_stop)
6659       return E_FILE_FORMAT_INVALID;
6660 
6661     if ((pos + len) > avail)
6662       return E_BUFFER_NOT_FULL;
6663 
6664     const long long size = ReadUInt(pReader, pos, len);
6665 
6666     if (size < 0)  // error
6667       return static_cast<long>(size);
6668 
6669     pos += len;  // consume size field
6670 
6671     // pos now points to start of sub-block group payload
6672 
6673     if (pos > payload_stop)
6674       return E_FILE_FORMAT_INVALID;
6675 
6676     if (size == 0)  // weird
6677       continue;
6678 
6679     const long long unknown_size = (1LL << (7 * len)) - 1;
6680 
6681     if (size == unknown_size)
6682       return E_FILE_FORMAT_INVALID;
6683 
6684     if (id == 0x35A2) {  // DiscardPadding
6685       status = UnserializeInt(pReader, pos, size, discard_padding);
6686 
6687       if (status < 0)  // error
6688         return status;
6689     }
6690 
6691     if (id != 0x21) {  // sub-part of BlockGroup is not a Block
6692       pos += size;  // consume sub-part of block group
6693 
6694       if (pos > payload_stop)
6695         return E_FILE_FORMAT_INVALID;
6696 
6697       continue;
6698     }
6699 
6700     const long long block_stop = pos + size;
6701 
6702     if (block_stop > payload_stop)
6703       return E_FILE_FORMAT_INVALID;
6704 
6705     // parse track number
6706 
6707     if ((pos + 1) > avail) {
6708       len = 1;
6709       return E_BUFFER_NOT_FULL;
6710     }
6711 
6712     result = GetUIntLength(pReader, pos, len);
6713 
6714     if (result < 0)  // error
6715       return static_cast<long>(result);
6716 
6717     if (result > 0)  // weird
6718       return E_BUFFER_NOT_FULL;
6719 
6720     if ((pos + len) > block_stop)
6721       return E_FILE_FORMAT_INVALID;
6722 
6723     if ((pos + len) > avail)
6724       return E_BUFFER_NOT_FULL;
6725 
6726     const long long track = ReadUInt(pReader, pos, len);
6727 
6728     if (track < 0)  // error
6729       return static_cast<long>(track);
6730 
6731     if (track == 0)
6732       return E_FILE_FORMAT_INVALID;
6733 
6734 #if 0
6735         //TODO(matthewjheaney)
6736         //This turned out to be too conservative.  The problem is that
6737         //if we see a track header in the tracks element with an unsupported
6738         //track type, we throw that track header away, so it is not present
6739         //in the track map.  But even though we don't understand the track
6740         //header, there are still blocks in the cluster with that track
6741         //number.  It was our decision to ignore that track header, so it's
6742         //up to us to deal with blocks associated with that track -- we
6743         //cannot simply report an error since technically there's nothing
6744         //wrong with the file.
6745         //
6746         //For now we go ahead and finish the parse, creating a block entry
6747         //for this block.  This is somewhat wasteful, because without a
6748         //track header there's nothing you can do with the block. What
6749         //we really need here is a special return value that indicates to
6750         //the caller that he should ignore this particular block, and
6751         //continue parsing.
6752 
6753         const Tracks* const pTracks = m_pSegment->GetTracks();
6754         assert(pTracks);
6755 
6756         const long tn = static_cast<long>(track);
6757 
6758         const Track* const pTrack = pTracks->GetTrackByNumber(tn);
6759 
6760         if (pTrack == NULL)
6761             return E_FILE_FORMAT_INVALID;
6762 #endif
6763 
6764     pos += len;  // consume track number
6765 
6766     if ((pos + 2) > block_stop)
6767       return E_FILE_FORMAT_INVALID;
6768 
6769     if ((pos + 2) > avail) {
6770       len = 2;
6771       return E_BUFFER_NOT_FULL;
6772     }
6773 
6774     pos += 2;  // consume timecode
6775 
6776     if ((pos + 1) > block_stop)
6777       return E_FILE_FORMAT_INVALID;
6778 
6779     if ((pos + 1) > avail) {
6780       len = 1;
6781       return E_BUFFER_NOT_FULL;
6782     }
6783 
6784     unsigned char flags;
6785 
6786     status = pReader->Read(pos, 1, &flags);
6787 
6788     if (status < 0) {  // error or underflow
6789       len = 1;
6790       return status;
6791     }
6792 
6793     ++pos;  // consume flags byte
6794     assert(pos <= avail);
6795 
6796     if (pos >= block_stop)
6797       return E_FILE_FORMAT_INVALID;
6798 
6799     const int lacing = int(flags & 0x06) >> 1;
6800 
6801     if ((lacing != 0) && (block_stop > avail)) {
6802       len = static_cast<long>(block_stop - pos);
6803       return E_BUFFER_NOT_FULL;
6804     }
6805 
6806     pos = block_stop;  // consume block-part of block group
6807     assert(pos <= payload_stop);
6808   }
6809 
6810   assert(pos == payload_stop);
6811 
6812   status = CreateBlock(0x20,  // BlockGroup ID
6813                        payload_start, payload_size, discard_padding);
6814   if (status != 0)
6815     return status;
6816 
6817   m_pos = payload_stop;
6818 
6819   return 0;  // success
6820 }
6821 
GetEntry(long index,const mkvparser::BlockEntry * & pEntry) const6822 long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
6823   assert(m_pos >= m_element_start);
6824 
6825   pEntry = NULL;
6826 
6827   if (index < 0)
6828     return -1;  // generic error
6829 
6830   if (m_entries_count < 0)
6831     return E_BUFFER_NOT_FULL;
6832 
6833   assert(m_entries);
6834   assert(m_entries_size > 0);
6835   assert(m_entries_count <= m_entries_size);
6836 
6837   if (index < m_entries_count) {
6838     pEntry = m_entries[index];
6839     assert(pEntry);
6840 
6841     return 1;  // found entry
6842   }
6843 
6844   if (m_element_size < 0)  // we don't know cluster end yet
6845     return E_BUFFER_NOT_FULL;  // underflow
6846 
6847   const long long element_stop = m_element_start + m_element_size;
6848 
6849   if (m_pos >= element_stop)
6850     return 0;  // nothing left to parse
6851 
6852   return E_BUFFER_NOT_FULL;  // underflow, since more remains to be parsed
6853 }
6854 
Create(Segment * pSegment,long idx,long long off)6855 Cluster* Cluster::Create(Segment* pSegment, long idx, long long off)
6856 // long long element_size)
6857 {
6858   assert(pSegment);
6859   assert(off >= 0);
6860 
6861   const long long element_start = pSegment->m_start + off;
6862 
6863   Cluster* const pCluster = new Cluster(pSegment, idx, element_start);
6864   // element_size);
6865   assert(pCluster);
6866 
6867   return pCluster;
6868 }
6869 
Cluster()6870 Cluster::Cluster()
6871     : m_pSegment(NULL),
6872       m_element_start(0),
6873       m_index(0),
6874       m_pos(0),
6875       m_element_size(0),
6876       m_timecode(0),
6877       m_entries(NULL),
6878       m_entries_size(0),
6879       m_entries_count(0)  // means "no entries"
6880 {}
6881 
Cluster(Segment * pSegment,long idx,long long element_start)6882 Cluster::Cluster(Segment* pSegment, long idx, long long element_start
6883                  /* long long element_size */)
6884     : m_pSegment(pSegment),
6885       m_element_start(element_start),
6886       m_index(idx),
6887       m_pos(element_start),
6888       m_element_size(-1 /* element_size */),
6889       m_timecode(-1),
6890       m_entries(NULL),
6891       m_entries_size(0),
6892       m_entries_count(-1)  // means "has not been parsed yet"
6893 {}
6894 
~Cluster()6895 Cluster::~Cluster() {
6896   if (m_entries_count <= 0)
6897     return;
6898 
6899   BlockEntry** i = m_entries;
6900   BlockEntry** const j = m_entries + m_entries_count;
6901 
6902   while (i != j) {
6903     BlockEntry* p = *i++;
6904     assert(p);
6905 
6906     delete p;
6907   }
6908 
6909   delete[] m_entries;
6910 }
6911 
EOS() const6912 bool Cluster::EOS() const { return (m_pSegment == NULL); }
6913 
GetIndex() const6914 long Cluster::GetIndex() const { return m_index; }
6915 
GetPosition() const6916 long long Cluster::GetPosition() const {
6917   const long long pos = m_element_start - m_pSegment->m_start;
6918   assert(pos >= 0);
6919 
6920   return pos;
6921 }
6922 
GetElementSize() const6923 long long Cluster::GetElementSize() const { return m_element_size; }
6924 
6925 #if 0
6926 bool Cluster::HasBlockEntries(
6927     const Segment* pSegment,
6928     long long off) {
6929     assert(pSegment);
6930     assert(off >= 0);  //relative to start of segment payload
6931 
6932     IMkvReader* const pReader = pSegment->m_pReader;
6933 
6934     long long pos = pSegment->m_start + off;  //absolute
6935     long long size;
6936 
6937     {
6938         long len;
6939 
6940         const long long id = ReadUInt(pReader, pos, len);
6941         (void)id;
6942         assert(id >= 0);
6943         assert(id == 0x0F43B675);  //Cluster ID
6944 
6945         pos += len;  //consume id
6946 
6947         size = ReadUInt(pReader, pos, len);
6948         assert(size > 0);
6949 
6950         pos += len;  //consume size
6951 
6952         //pos now points to start of payload
6953     }
6954 
6955     const long long stop = pos + size;
6956 
6957     while (pos < stop)
6958     {
6959         long len;
6960 
6961         const long long id = ReadUInt(pReader, pos, len);
6962         assert(id >= 0);  //TODO
6963         assert((pos + len) <= stop);
6964 
6965         pos += len;  //consume id
6966 
6967         const long long size = ReadUInt(pReader, pos, len);
6968         assert(size >= 0);  //TODO
6969         assert((pos + len) <= stop);
6970 
6971         pos += len;  //consume size
6972 
6973         if (id == 0x20)  //BlockGroup ID
6974             return true;
6975 
6976         if (id == 0x23)  //SimpleBlock ID
6977             return true;
6978 
6979         pos += size;  //consume payload
6980         assert(pos <= stop);
6981     }
6982 
6983     return false;
6984 }
6985 #endif
6986 
HasBlockEntries(const Segment * pSegment,long long off,long long & pos,long & len)6987 long Cluster::HasBlockEntries(
6988     const Segment* pSegment,
6989     long long off,  // relative to start of segment payload
6990     long long& pos, long& len) {
6991   assert(pSegment);
6992   assert(off >= 0);  // relative to segment
6993 
6994   IMkvReader* const pReader = pSegment->m_pReader;
6995 
6996   long long total, avail;
6997 
6998   long status = pReader->Length(&total, &avail);
6999 
7000   if (status < 0)  // error
7001     return status;
7002 
7003   assert((total < 0) || (avail <= total));
7004 
7005   pos = pSegment->m_start + off;  // absolute
7006 
7007   if ((total >= 0) && (pos >= total))
7008     return 0;  // we don't even have a complete cluster
7009 
7010   const long long segment_stop =
7011       (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
7012 
7013   long long cluster_stop = -1;  // interpreted later to mean "unknown size"
7014 
7015   {
7016     if ((pos + 1) > avail) {
7017       len = 1;
7018       return E_BUFFER_NOT_FULL;
7019     }
7020 
7021     long long result = GetUIntLength(pReader, pos, len);
7022 
7023     if (result < 0)  // error
7024       return static_cast<long>(result);
7025 
7026     if (result > 0)  // need more data
7027       return E_BUFFER_NOT_FULL;
7028 
7029     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
7030       return E_FILE_FORMAT_INVALID;
7031 
7032     if ((total >= 0) && ((pos + len) > total))
7033       return 0;
7034 
7035     if ((pos + len) > avail)
7036       return E_BUFFER_NOT_FULL;
7037 
7038     const long long id = ReadUInt(pReader, pos, len);
7039 
7040     if (id < 0)  // error
7041       return static_cast<long>(id);
7042 
7043     if (id != 0x0F43B675)  // weird: not cluster ID
7044       return -1;  // generic error
7045 
7046     pos += len;  // consume Cluster ID field
7047 
7048     // read size field
7049 
7050     if ((pos + 1) > avail) {
7051       len = 1;
7052       return E_BUFFER_NOT_FULL;
7053     }
7054 
7055     result = GetUIntLength(pReader, pos, len);
7056 
7057     if (result < 0)  // error
7058       return static_cast<long>(result);
7059 
7060     if (result > 0)  // weird
7061       return E_BUFFER_NOT_FULL;
7062 
7063     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
7064       return E_FILE_FORMAT_INVALID;
7065 
7066     if ((total >= 0) && ((pos + len) > total))
7067       return 0;
7068 
7069     if ((pos + len) > avail)
7070       return E_BUFFER_NOT_FULL;
7071 
7072     const long long size = ReadUInt(pReader, pos, len);
7073 
7074     if (size < 0)  // error
7075       return static_cast<long>(size);
7076 
7077     if (size == 0)
7078       return 0;  // cluster does not have entries
7079 
7080     pos += len;  // consume size field
7081 
7082     // pos now points to start of payload
7083 
7084     const long long unknown_size = (1LL << (7 * len)) - 1;
7085 
7086     if (size != unknown_size) {
7087       cluster_stop = pos + size;
7088       assert(cluster_stop >= 0);
7089 
7090       if ((segment_stop >= 0) && (cluster_stop > segment_stop))
7091         return E_FILE_FORMAT_INVALID;
7092 
7093       if ((total >= 0) && (cluster_stop > total))
7094         // return E_FILE_FORMAT_INVALID;  //too conservative
7095         return 0;  // cluster does not have any entries
7096     }
7097   }
7098 
7099   for (;;) {
7100     if ((cluster_stop >= 0) && (pos >= cluster_stop))
7101       return 0;  // no entries detected
7102 
7103     if ((pos + 1) > avail) {
7104       len = 1;
7105       return E_BUFFER_NOT_FULL;
7106     }
7107 
7108     long long result = GetUIntLength(pReader, pos, len);
7109 
7110     if (result < 0)  // error
7111       return static_cast<long>(result);
7112 
7113     if (result > 0)  // need more data
7114       return E_BUFFER_NOT_FULL;
7115 
7116     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7117       return E_FILE_FORMAT_INVALID;
7118 
7119     if ((pos + len) > avail)
7120       return E_BUFFER_NOT_FULL;
7121 
7122     const long long id = ReadUInt(pReader, pos, len);
7123 
7124     if (id < 0)  // error
7125       return static_cast<long>(id);
7126 
7127     // This is the distinguished set of ID's we use to determine
7128     // that we have exhausted the sub-element's inside the cluster
7129     // whose ID we parsed earlier.
7130 
7131     if (id == 0x0F43B675)  // Cluster ID
7132       return 0;  // no entries found
7133 
7134     if (id == 0x0C53BB6B)  // Cues ID
7135       return 0;  // no entries found
7136 
7137     pos += len;  // consume id field
7138 
7139     if ((cluster_stop >= 0) && (pos >= cluster_stop))
7140       return E_FILE_FORMAT_INVALID;
7141 
7142     // read size field
7143 
7144     if ((pos + 1) > avail) {
7145       len = 1;
7146       return E_BUFFER_NOT_FULL;
7147     }
7148 
7149     result = GetUIntLength(pReader, pos, len);
7150 
7151     if (result < 0)  // error
7152       return static_cast<long>(result);
7153 
7154     if (result > 0)  // underflow
7155       return E_BUFFER_NOT_FULL;
7156 
7157     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7158       return E_FILE_FORMAT_INVALID;
7159 
7160     if ((pos + len) > avail)
7161       return E_BUFFER_NOT_FULL;
7162 
7163     const long long size = ReadUInt(pReader, pos, len);
7164 
7165     if (size < 0)  // error
7166       return static_cast<long>(size);
7167 
7168     pos += len;  // consume size field
7169 
7170     // pos now points to start of payload
7171 
7172     if ((cluster_stop >= 0) && (pos > cluster_stop))
7173       return E_FILE_FORMAT_INVALID;
7174 
7175     if (size == 0)  // weird
7176       continue;
7177 
7178     const long long unknown_size = (1LL << (7 * len)) - 1;
7179 
7180     if (size == unknown_size)
7181       return E_FILE_FORMAT_INVALID;  // not supported inside cluster
7182 
7183     if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
7184       return E_FILE_FORMAT_INVALID;
7185 
7186     if (id == 0x20)  // BlockGroup ID
7187       return 1;  // have at least one entry
7188 
7189     if (id == 0x23)  // SimpleBlock ID
7190       return 1;  // have at least one entry
7191 
7192     pos += size;  // consume payload
7193     assert((cluster_stop < 0) || (pos <= cluster_stop));
7194   }
7195 }
7196 
GetTimeCode() const7197 long long Cluster::GetTimeCode() const {
7198   long long pos;
7199   long len;
7200 
7201   const long status = Load(pos, len);
7202 
7203   if (status < 0)  // error
7204     return status;
7205 
7206   return m_timecode;
7207 }
7208 
GetTime() const7209 long long Cluster::GetTime() const {
7210   const long long tc = GetTimeCode();
7211 
7212   if (tc < 0)
7213     return tc;
7214 
7215   const SegmentInfo* const pInfo = m_pSegment->GetInfo();
7216   assert(pInfo);
7217 
7218   const long long scale = pInfo->GetTimeCodeScale();
7219   assert(scale >= 1);
7220 
7221   const long long t = m_timecode * scale;
7222 
7223   return t;
7224 }
7225 
GetFirstTime() const7226 long long Cluster::GetFirstTime() const {
7227   const BlockEntry* pEntry;
7228 
7229   const long status = GetFirst(pEntry);
7230 
7231   if (status < 0)  // error
7232     return status;
7233 
7234   if (pEntry == NULL)  // empty cluster
7235     return GetTime();
7236 
7237   const Block* const pBlock = pEntry->GetBlock();
7238   assert(pBlock);
7239 
7240   return pBlock->GetTime(this);
7241 }
7242 
GetLastTime() const7243 long long Cluster::GetLastTime() const {
7244   const BlockEntry* pEntry;
7245 
7246   const long status = GetLast(pEntry);
7247 
7248   if (status < 0)  // error
7249     return status;
7250 
7251   if (pEntry == NULL)  // empty cluster
7252     return GetTime();
7253 
7254   const Block* const pBlock = pEntry->GetBlock();
7255   assert(pBlock);
7256 
7257   return pBlock->GetTime(this);
7258 }
7259 
CreateBlock(long long id,long long pos,long long size,long long discard_padding)7260 long Cluster::CreateBlock(long long id,
7261                           long long pos,  // absolute pos of payload
7262                           long long size, long long discard_padding) {
7263   assert((id == 0x20) || (id == 0x23));  // BlockGroup or SimpleBlock
7264 
7265   if (m_entries_count < 0) {  // haven't parsed anything yet
7266     assert(m_entries == NULL);
7267     assert(m_entries_size == 0);
7268 
7269     m_entries_size = 1024;
7270     m_entries = new BlockEntry* [m_entries_size];
7271 
7272     m_entries_count = 0;
7273   } else {
7274     assert(m_entries);
7275     assert(m_entries_size > 0);
7276     assert(m_entries_count <= m_entries_size);
7277 
7278     if (m_entries_count >= m_entries_size) {
7279       const long entries_size = 2 * m_entries_size;
7280 
7281       BlockEntry** const entries = new BlockEntry* [entries_size];
7282       assert(entries);
7283 
7284       BlockEntry** src = m_entries;
7285       BlockEntry** const src_end = src + m_entries_count;
7286 
7287       BlockEntry** dst = entries;
7288 
7289       while (src != src_end)
7290         *dst++ = *src++;
7291 
7292       delete[] m_entries;
7293 
7294       m_entries = entries;
7295       m_entries_size = entries_size;
7296     }
7297   }
7298 
7299   if (id == 0x20)  // BlockGroup ID
7300     return CreateBlockGroup(pos, size, discard_padding);
7301   else  // SimpleBlock ID
7302     return CreateSimpleBlock(pos, size);
7303 }
7304 
CreateBlockGroup(long long start_offset,long long size,long long discard_padding)7305 long Cluster::CreateBlockGroup(long long start_offset, long long size,
7306                                long long discard_padding) {
7307   assert(m_entries);
7308   assert(m_entries_size > 0);
7309   assert(m_entries_count >= 0);
7310   assert(m_entries_count < m_entries_size);
7311 
7312   IMkvReader* const pReader = m_pSegment->m_pReader;
7313 
7314   long long pos = start_offset;
7315   const long long stop = start_offset + size;
7316 
7317   // For WebM files, there is a bias towards previous reference times
7318   //(in order to support alt-ref frames, which refer back to the previous
7319   // keyframe).  Normally a 0 value is not possible, but here we tenatively
7320   // allow 0 as the value of a reference frame, with the interpretation
7321   // that this is a "previous" reference time.
7322 
7323   long long prev = 1;  // nonce
7324   long long next = 0;  // nonce
7325   long long duration = -1;  // really, this is unsigned
7326 
7327   long long bpos = -1;
7328   long long bsize = -1;
7329 
7330   while (pos < stop) {
7331     long len;
7332     const long long id = ReadUInt(pReader, pos, len);
7333     assert(id >= 0);  // TODO
7334     assert((pos + len) <= stop);
7335 
7336     pos += len;  // consume ID
7337 
7338     const long long size = ReadUInt(pReader, pos, len);
7339     assert(size >= 0);  // TODO
7340     assert((pos + len) <= stop);
7341 
7342     pos += len;  // consume size
7343 
7344     if (id == 0x21) {  // Block ID
7345       if (bpos < 0) {  // Block ID
7346         bpos = pos;
7347         bsize = size;
7348       }
7349     } else if (id == 0x1B) {  // Duration ID
7350       assert(size <= 8);
7351 
7352       duration = UnserializeUInt(pReader, pos, size);
7353       assert(duration >= 0);  // TODO
7354     } else if (id == 0x7B) {  // ReferenceBlock
7355       assert(size <= 8);
7356       const long size_ = static_cast<long>(size);
7357 
7358       long long time;
7359 
7360       long status = UnserializeInt(pReader, pos, size_, time);
7361       assert(status == 0);
7362       if (status != 0)
7363         return -1;
7364 
7365       if (time <= 0)  // see note above
7366         prev = time;
7367       else  // weird
7368         next = time;
7369     }
7370 
7371     pos += size;  // consume payload
7372     assert(pos <= stop);
7373   }
7374 
7375   assert(pos == stop);
7376   assert(bpos >= 0);
7377   assert(bsize >= 0);
7378 
7379   const long idx = m_entries_count;
7380 
7381   BlockEntry** const ppEntry = m_entries + idx;
7382   BlockEntry*& pEntry = *ppEntry;
7383 
7384   pEntry = new (std::nothrow)
7385       BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
7386 
7387   if (pEntry == NULL)
7388     return -1;  // generic error
7389 
7390   BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
7391 
7392   const long status = p->Parse();
7393 
7394   if (status == 0) {  // success
7395     ++m_entries_count;
7396     return 0;
7397   }
7398 
7399   delete pEntry;
7400   pEntry = 0;
7401 
7402   return status;
7403 }
7404 
CreateSimpleBlock(long long st,long long sz)7405 long Cluster::CreateSimpleBlock(long long st, long long sz) {
7406   assert(m_entries);
7407   assert(m_entries_size > 0);
7408   assert(m_entries_count >= 0);
7409   assert(m_entries_count < m_entries_size);
7410 
7411   const long idx = m_entries_count;
7412 
7413   BlockEntry** const ppEntry = m_entries + idx;
7414   BlockEntry*& pEntry = *ppEntry;
7415 
7416   pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
7417 
7418   if (pEntry == NULL)
7419     return -1;  // generic error
7420 
7421   SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
7422 
7423   const long status = p->Parse();
7424 
7425   if (status == 0) {
7426     ++m_entries_count;
7427     return 0;
7428   }
7429 
7430   delete pEntry;
7431   pEntry = 0;
7432 
7433   return status;
7434 }
7435 
GetFirst(const BlockEntry * & pFirst) const7436 long Cluster::GetFirst(const BlockEntry*& pFirst) const {
7437   if (m_entries_count <= 0) {
7438     long long pos;
7439     long len;
7440 
7441     const long status = Parse(pos, len);
7442 
7443     if (status < 0) {  // error
7444       pFirst = NULL;
7445       return status;
7446     }
7447 
7448     if (m_entries_count <= 0) {  // empty cluster
7449       pFirst = NULL;
7450       return 0;
7451     }
7452   }
7453 
7454   assert(m_entries);
7455 
7456   pFirst = m_entries[0];
7457   assert(pFirst);
7458 
7459   return 0;  // success
7460 }
7461 
GetLast(const BlockEntry * & pLast) const7462 long Cluster::GetLast(const BlockEntry*& pLast) const {
7463   for (;;) {
7464     long long pos;
7465     long len;
7466 
7467     const long status = Parse(pos, len);
7468 
7469     if (status < 0) {  // error
7470       pLast = NULL;
7471       return status;
7472     }
7473 
7474     if (status > 0)  // no new block
7475       break;
7476   }
7477 
7478   if (m_entries_count <= 0) {
7479     pLast = NULL;
7480     return 0;
7481   }
7482 
7483   assert(m_entries);
7484 
7485   const long idx = m_entries_count - 1;
7486 
7487   pLast = m_entries[idx];
7488   assert(pLast);
7489 
7490   return 0;
7491 }
7492 
GetNext(const BlockEntry * pCurr,const BlockEntry * & pNext) const7493 long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const {
7494   assert(pCurr);
7495   assert(m_entries);
7496   assert(m_entries_count > 0);
7497 
7498   size_t idx = pCurr->GetIndex();
7499   assert(idx < size_t(m_entries_count));
7500   assert(m_entries[idx] == pCurr);
7501 
7502   ++idx;
7503 
7504   if (idx >= size_t(m_entries_count)) {
7505     long long pos;
7506     long len;
7507 
7508     const long status = Parse(pos, len);
7509 
7510     if (status < 0) {  // error
7511       pNext = NULL;
7512       return status;
7513     }
7514 
7515     if (status > 0) {
7516       pNext = NULL;
7517       return 0;
7518     }
7519 
7520     assert(m_entries);
7521     assert(m_entries_count > 0);
7522     assert(idx < size_t(m_entries_count));
7523   }
7524 
7525   pNext = m_entries[idx];
7526   assert(pNext);
7527 
7528   return 0;
7529 }
7530 
GetEntryCount() const7531 long Cluster::GetEntryCount() const { return m_entries_count; }
7532 
GetEntry(const Track * pTrack,long long time_ns) const7533 const BlockEntry* Cluster::GetEntry(const Track* pTrack,
7534                                     long long time_ns) const {
7535   assert(pTrack);
7536 
7537   if (m_pSegment == NULL)  // this is the special EOS cluster
7538     return pTrack->GetEOS();
7539 
7540 #if 0
7541 
7542     LoadBlockEntries();
7543 
7544     if ((m_entries == NULL) || (m_entries_count <= 0))
7545         return NULL;  //return EOS here?
7546 
7547     const BlockEntry* pResult = pTrack->GetEOS();
7548 
7549     BlockEntry** i = m_entries;
7550     assert(i);
7551 
7552     BlockEntry** const j = i + m_entries_count;
7553 
7554     while (i != j)
7555     {
7556         const BlockEntry* const pEntry = *i++;
7557         assert(pEntry);
7558         assert(!pEntry->EOS());
7559 
7560         const Block* const pBlock = pEntry->GetBlock();
7561         assert(pBlock);
7562 
7563         if (pBlock->GetTrackNumber() != pTrack->GetNumber())
7564             continue;
7565 
7566         if (pTrack->VetEntry(pEntry))
7567         {
7568             if (time_ns < 0)  //just want first candidate block
7569                 return pEntry;
7570 
7571             const long long ns = pBlock->GetTime(this);
7572 
7573             if (ns > time_ns)
7574                 break;
7575 
7576             pResult = pEntry;
7577         }
7578         else if (time_ns >= 0)
7579         {
7580             const long long ns = pBlock->GetTime(this);
7581 
7582             if (ns > time_ns)
7583                 break;
7584         }
7585     }
7586 
7587     return pResult;
7588 
7589 #else
7590 
7591   const BlockEntry* pResult = pTrack->GetEOS();
7592 
7593   long index = 0;
7594 
7595   for (;;) {
7596     if (index >= m_entries_count) {
7597       long long pos;
7598       long len;
7599 
7600       const long status = Parse(pos, len);
7601       assert(status >= 0);
7602 
7603       if (status > 0)  // completely parsed, and no more entries
7604         return pResult;
7605 
7606       if (status < 0)  // should never happen
7607         return 0;
7608 
7609       assert(m_entries);
7610       assert(index < m_entries_count);
7611     }
7612 
7613     const BlockEntry* const pEntry = m_entries[index];
7614     assert(pEntry);
7615     assert(!pEntry->EOS());
7616 
7617     const Block* const pBlock = pEntry->GetBlock();
7618     assert(pBlock);
7619 
7620     if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
7621       ++index;
7622       continue;
7623     }
7624 
7625     if (pTrack->VetEntry(pEntry)) {
7626       if (time_ns < 0)  // just want first candidate block
7627         return pEntry;
7628 
7629       const long long ns = pBlock->GetTime(this);
7630 
7631       if (ns > time_ns)
7632         return pResult;
7633 
7634       pResult = pEntry;  // have a candidate
7635     } else if (time_ns >= 0) {
7636       const long long ns = pBlock->GetTime(this);
7637 
7638       if (ns > time_ns)
7639         return pResult;
7640     }
7641 
7642     ++index;
7643   }
7644 
7645 #endif
7646 }
7647 
GetEntry(const CuePoint & cp,const CuePoint::TrackPosition & tp) const7648 const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
7649                                     const CuePoint::TrackPosition& tp) const {
7650   assert(m_pSegment);
7651 
7652 #if 0
7653 
7654     LoadBlockEntries();
7655 
7656     if (m_entries == NULL)
7657         return NULL;
7658 
7659     const long long count = m_entries_count;
7660 
7661     if (count <= 0)
7662         return NULL;
7663 
7664     const long long tc = cp.GetTimeCode();
7665 
7666     if ((tp.m_block > 0) && (tp.m_block <= count))
7667     {
7668         const size_t block = static_cast<size_t>(tp.m_block);
7669         const size_t index = block - 1;
7670 
7671         const BlockEntry* const pEntry = m_entries[index];
7672         assert(pEntry);
7673         assert(!pEntry->EOS());
7674 
7675         const Block* const pBlock = pEntry->GetBlock();
7676         assert(pBlock);
7677 
7678         if ((pBlock->GetTrackNumber() == tp.m_track) &&
7679             (pBlock->GetTimeCode(this) == tc))
7680         {
7681             return pEntry;
7682         }
7683     }
7684 
7685     const BlockEntry* const* i = m_entries;
7686     const BlockEntry* const* const j = i + count;
7687 
7688     while (i != j)
7689     {
7690 #ifdef _DEBUG
7691         const ptrdiff_t idx = i - m_entries;
7692         idx;
7693 #endif
7694 
7695         const BlockEntry* const pEntry = *i++;
7696         assert(pEntry);
7697         assert(!pEntry->EOS());
7698 
7699         const Block* const pBlock = pEntry->GetBlock();
7700         assert(pBlock);
7701 
7702         if (pBlock->GetTrackNumber() != tp.m_track)
7703             continue;
7704 
7705         const long long tc_ = pBlock->GetTimeCode(this);
7706         assert(tc_ >= 0);
7707 
7708         if (tc_ < tc)
7709             continue;
7710 
7711         if (tc_ > tc)
7712             return NULL;
7713 
7714         const Tracks* const pTracks = m_pSegment->GetTracks();
7715         assert(pTracks);
7716 
7717         const long tn = static_cast<long>(tp.m_track);
7718         const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7719 
7720         if (pTrack == NULL)
7721             return NULL;
7722 
7723         const long long type = pTrack->GetType();
7724 
7725         if (type == 2)  //audio
7726             return pEntry;
7727 
7728         if (type != 1)  //not video
7729             return NULL;
7730 
7731         if (!pBlock->IsKey())
7732             return NULL;
7733 
7734         return pEntry;
7735     }
7736 
7737     return NULL;
7738 
7739 #else
7740 
7741   const long long tc = cp.GetTimeCode();
7742 
7743   if (tp.m_block > 0) {
7744     const long block = static_cast<long>(tp.m_block);
7745     const long index = block - 1;
7746 
7747     while (index >= m_entries_count) {
7748       long long pos;
7749       long len;
7750 
7751       const long status = Parse(pos, len);
7752 
7753       if (status < 0)  // TODO: can this happen?
7754         return NULL;
7755 
7756       if (status > 0)  // nothing remains to be parsed
7757         return NULL;
7758     }
7759 
7760     const BlockEntry* const pEntry = m_entries[index];
7761     assert(pEntry);
7762     assert(!pEntry->EOS());
7763 
7764     const Block* const pBlock = pEntry->GetBlock();
7765     assert(pBlock);
7766 
7767     if ((pBlock->GetTrackNumber() == tp.m_track) &&
7768         (pBlock->GetTimeCode(this) == tc)) {
7769       return pEntry;
7770     }
7771   }
7772 
7773   long index = 0;
7774 
7775   for (;;) {
7776     if (index >= m_entries_count) {
7777       long long pos;
7778       long len;
7779 
7780       const long status = Parse(pos, len);
7781 
7782       if (status < 0)  // TODO: can this happen?
7783         return NULL;
7784 
7785       if (status > 0)  // nothing remains to be parsed
7786         return NULL;
7787 
7788       assert(m_entries);
7789       assert(index < m_entries_count);
7790     }
7791 
7792     const BlockEntry* const pEntry = m_entries[index];
7793     assert(pEntry);
7794     assert(!pEntry->EOS());
7795 
7796     const Block* const pBlock = pEntry->GetBlock();
7797     assert(pBlock);
7798 
7799     if (pBlock->GetTrackNumber() != tp.m_track) {
7800       ++index;
7801       continue;
7802     }
7803 
7804     const long long tc_ = pBlock->GetTimeCode(this);
7805 
7806     if (tc_ < tc) {
7807       ++index;
7808       continue;
7809     }
7810 
7811     if (tc_ > tc)
7812       return NULL;
7813 
7814     const Tracks* const pTracks = m_pSegment->GetTracks();
7815     assert(pTracks);
7816 
7817     const long tn = static_cast<long>(tp.m_track);
7818     const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7819 
7820     if (pTrack == NULL)
7821       return NULL;
7822 
7823     const long long type = pTrack->GetType();
7824 
7825     if (type == 2)  // audio
7826       return pEntry;
7827 
7828     if (type != 1)  // not video
7829       return NULL;
7830 
7831     if (!pBlock->IsKey())
7832       return NULL;
7833 
7834     return pEntry;
7835   }
7836 
7837 #endif
7838 }
7839 
7840 #if 0
7841 const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const
7842 {
7843     assert(pTrack);
7844 
7845     if (m_pSegment == NULL)  //EOS
7846         return pTrack->GetEOS();
7847 
7848     LoadBlockEntries();
7849 
7850     if ((m_entries == NULL) || (m_entries_count <= 0))
7851         return pTrack->GetEOS();
7852 
7853     BlockEntry** i = m_entries + m_entries_count;
7854     BlockEntry** const j = m_entries;
7855 
7856     while (i != j)
7857     {
7858         const BlockEntry* const pEntry = *--i;
7859         assert(pEntry);
7860         assert(!pEntry->EOS());
7861 
7862         const Block* const pBlock = pEntry->GetBlock();
7863         assert(pBlock);
7864 
7865         if (pBlock->GetTrackNumber() != pTrack->GetNumber())
7866             continue;
7867 
7868         if (pBlock->IsKey())
7869             return pEntry;
7870     }
7871 
7872     return pTrack->GetEOS();  //no satisfactory block found
7873 }
7874 #endif
7875 
BlockEntry(Cluster * p,long idx)7876 BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
7877 
~BlockEntry()7878 BlockEntry::~BlockEntry() {}
7879 
EOS() const7880 bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); }
7881 
GetCluster() const7882 const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
7883 
GetIndex() const7884 long BlockEntry::GetIndex() const { return m_index; }
7885 
SimpleBlock(Cluster * pCluster,long idx,long long start,long long size)7886 SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
7887                          long long size)
7888     : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
7889 
Parse()7890 long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
7891 
GetKind() const7892 BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
7893 
GetBlock() const7894 const Block* SimpleBlock::GetBlock() const { return &m_block; }
7895 
BlockGroup(Cluster * pCluster,long idx,long long block_start,long long block_size,long long prev,long long next,long long duration,long long discard_padding)7896 BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start,
7897                        long long block_size, long long prev, long long next,
7898                        long long duration, long long discard_padding)
7899     : BlockEntry(pCluster, idx),
7900       m_block(block_start, block_size, discard_padding),
7901       m_prev(prev),
7902       m_next(next),
7903       m_duration(duration) {}
7904 
Parse()7905 long BlockGroup::Parse() {
7906   const long status = m_block.Parse(m_pCluster);
7907 
7908   if (status)
7909     return status;
7910 
7911   m_block.SetKey((m_prev > 0) && (m_next <= 0));
7912 
7913   return 0;
7914 }
7915 
7916 #if 0
7917 void BlockGroup::ParseBlock(long long start, long long size)
7918 {
7919     IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
7920 
7921     Block* const pBlock = new Block(start, size, pReader);
7922     assert(pBlock);  //TODO
7923 
7924     //TODO: the Matroska spec says you have multiple blocks within the
7925     //same block group, with blocks ranked by priority (the flag bits).
7926 
7927     assert(m_pBlock == NULL);
7928     m_pBlock = pBlock;
7929 }
7930 #endif
7931 
GetKind() const7932 BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
7933 
GetBlock() const7934 const Block* BlockGroup::GetBlock() const { return &m_block; }
7935 
GetPrevTimeCode() const7936 long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
7937 
GetNextTimeCode() const7938 long long BlockGroup::GetNextTimeCode() const { return m_next; }
7939 
GetDurationTimeCode() const7940 long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
7941 
Block(long long start,long long size_,long long discard_padding)7942 Block::Block(long long start, long long size_, long long discard_padding)
7943     : m_start(start),
7944       m_size(size_),
7945       m_track(0),
7946       m_timecode(-1),
7947       m_flags(0),
7948       m_frames(NULL),
7949       m_frame_count(-1),
7950       m_discard_padding(discard_padding) {}
7951 
~Block()7952 Block::~Block() { delete[] m_frames; }
7953 
Parse(const Cluster * pCluster)7954 long Block::Parse(const Cluster* pCluster) {
7955   if (pCluster == NULL)
7956     return -1;
7957 
7958   if (pCluster->m_pSegment == NULL)
7959     return -1;
7960 
7961   assert(m_start >= 0);
7962   assert(m_size >= 0);
7963   assert(m_track <= 0);
7964   assert(m_frames == NULL);
7965   assert(m_frame_count <= 0);
7966 
7967   long long pos = m_start;
7968   const long long stop = m_start + m_size;
7969 
7970   long len;
7971 
7972   IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;
7973 
7974   m_track = ReadUInt(pReader, pos, len);
7975 
7976   if (m_track <= 0)
7977     return E_FILE_FORMAT_INVALID;
7978 
7979   if ((pos + len) > stop)
7980     return E_FILE_FORMAT_INVALID;
7981 
7982   pos += len;  // consume track number
7983 
7984   if ((stop - pos) < 2)
7985     return E_FILE_FORMAT_INVALID;
7986 
7987   long status;
7988   long long value;
7989 
7990   status = UnserializeInt(pReader, pos, 2, value);
7991 
7992   if (status)
7993     return E_FILE_FORMAT_INVALID;
7994 
7995   if (value < SHRT_MIN)
7996     return E_FILE_FORMAT_INVALID;
7997 
7998   if (value > SHRT_MAX)
7999     return E_FILE_FORMAT_INVALID;
8000 
8001   m_timecode = static_cast<short>(value);
8002 
8003   pos += 2;
8004 
8005   if ((stop - pos) <= 0)
8006     return E_FILE_FORMAT_INVALID;
8007 
8008   status = pReader->Read(pos, 1, &m_flags);
8009 
8010   if (status)
8011     return E_FILE_FORMAT_INVALID;
8012 
8013   const int lacing = int(m_flags & 0x06) >> 1;
8014 
8015   ++pos;  // consume flags byte
8016 
8017   if (lacing == 0) {  // no lacing
8018     if (pos > stop)
8019       return E_FILE_FORMAT_INVALID;
8020 
8021     m_frame_count = 1;
8022     m_frames = new Frame[m_frame_count];
8023 
8024     Frame& f = m_frames[0];
8025     f.pos = pos;
8026 
8027     const long long frame_size = stop - pos;
8028 
8029     if (frame_size > LONG_MAX)
8030       return E_FILE_FORMAT_INVALID;
8031 
8032     f.len = static_cast<long>(frame_size);
8033 
8034     return 0;  // success
8035   }
8036 
8037   if (pos >= stop)
8038     return E_FILE_FORMAT_INVALID;
8039 
8040   unsigned char biased_count;
8041 
8042   status = pReader->Read(pos, 1, &biased_count);
8043 
8044   if (status)
8045     return E_FILE_FORMAT_INVALID;
8046 
8047   ++pos;  // consume frame count
8048   assert(pos <= stop);
8049 
8050   m_frame_count = int(biased_count) + 1;
8051 
8052   m_frames = new Frame[m_frame_count];
8053   assert(m_frames);
8054 
8055   if (lacing == 1) {  // Xiph
8056     Frame* pf = m_frames;
8057     Frame* const pf_end = pf + m_frame_count;
8058 
8059     long size = 0;
8060     int frame_count = m_frame_count;
8061 
8062     while (frame_count > 1) {
8063       long frame_size = 0;
8064 
8065       for (;;) {
8066         unsigned char val;
8067 
8068         if (pos >= stop)
8069           return E_FILE_FORMAT_INVALID;
8070 
8071         status = pReader->Read(pos, 1, &val);
8072 
8073         if (status)
8074           return E_FILE_FORMAT_INVALID;
8075 
8076         ++pos;  // consume xiph size byte
8077 
8078         frame_size += val;
8079 
8080         if (val < 255)
8081           break;
8082       }
8083 
8084       Frame& f = *pf++;
8085       assert(pf < pf_end);
8086 
8087       f.pos = 0;  // patch later
8088 
8089       f.len = frame_size;
8090       size += frame_size;  // contribution of this frame
8091 
8092       --frame_count;
8093     }
8094 
8095     assert(pf < pf_end);
8096     assert(pos <= stop);
8097 
8098     {
8099       Frame& f = *pf++;
8100 
8101       if (pf != pf_end)
8102         return E_FILE_FORMAT_INVALID;
8103 
8104       f.pos = 0;  // patch later
8105 
8106       const long long total_size = stop - pos;
8107 
8108       if (total_size < size)
8109         return E_FILE_FORMAT_INVALID;
8110 
8111       const long long frame_size = total_size - size;
8112 
8113       if (frame_size > LONG_MAX)
8114         return E_FILE_FORMAT_INVALID;
8115 
8116       f.len = static_cast<long>(frame_size);
8117     }
8118 
8119     pf = m_frames;
8120     while (pf != pf_end) {
8121       Frame& f = *pf++;
8122       assert((pos + f.len) <= stop);
8123 
8124       f.pos = pos;
8125       pos += f.len;
8126     }
8127 
8128     assert(pos == stop);
8129   } else if (lacing == 2) {  // fixed-size lacing
8130     const long long total_size = stop - pos;
8131 
8132     if ((total_size % m_frame_count) != 0)
8133       return E_FILE_FORMAT_INVALID;
8134 
8135     const long long frame_size = total_size / m_frame_count;
8136 
8137     if (frame_size > LONG_MAX)
8138       return E_FILE_FORMAT_INVALID;
8139 
8140     Frame* pf = m_frames;
8141     Frame* const pf_end = pf + m_frame_count;
8142 
8143     while (pf != pf_end) {
8144       assert((pos + frame_size) <= stop);
8145 
8146       Frame& f = *pf++;
8147 
8148       f.pos = pos;
8149       f.len = static_cast<long>(frame_size);
8150 
8151       pos += frame_size;
8152     }
8153 
8154     assert(pos == stop);
8155   } else {
8156     assert(lacing == 3);  // EBML lacing
8157 
8158     if (pos >= stop)
8159       return E_FILE_FORMAT_INVALID;
8160 
8161     long size = 0;
8162     int frame_count = m_frame_count;
8163 
8164     long long frame_size = ReadUInt(pReader, pos, len);
8165 
8166     if (frame_size < 0)
8167       return E_FILE_FORMAT_INVALID;
8168 
8169     if (frame_size > LONG_MAX)
8170       return E_FILE_FORMAT_INVALID;
8171 
8172     if ((pos + len) > stop)
8173       return E_FILE_FORMAT_INVALID;
8174 
8175     pos += len;  // consume length of size of first frame
8176 
8177     if ((pos + frame_size) > stop)
8178       return E_FILE_FORMAT_INVALID;
8179 
8180     Frame* pf = m_frames;
8181     Frame* const pf_end = pf + m_frame_count;
8182 
8183     {
8184       Frame& curr = *pf;
8185 
8186       curr.pos = 0;  // patch later
8187 
8188       curr.len = static_cast<long>(frame_size);
8189       size += curr.len;  // contribution of this frame
8190     }
8191 
8192     --frame_count;
8193 
8194     while (frame_count > 1) {
8195       if (pos >= stop)
8196         return E_FILE_FORMAT_INVALID;
8197 
8198       assert(pf < pf_end);
8199 
8200       const Frame& prev = *pf++;
8201       assert(prev.len == frame_size);
8202       if (prev.len != frame_size)
8203         return E_FILE_FORMAT_INVALID;
8204 
8205       assert(pf < pf_end);
8206 
8207       Frame& curr = *pf;
8208 
8209       curr.pos = 0;  // patch later
8210 
8211       const long long delta_size_ = ReadUInt(pReader, pos, len);
8212 
8213       if (delta_size_ < 0)
8214         return E_FILE_FORMAT_INVALID;
8215 
8216       if ((pos + len) > stop)
8217         return E_FILE_FORMAT_INVALID;
8218 
8219       pos += len;  // consume length of (delta) size
8220       assert(pos <= stop);
8221 
8222       const int exp = 7 * len - 1;
8223       const long long bias = (1LL << exp) - 1LL;
8224       const long long delta_size = delta_size_ - bias;
8225 
8226       frame_size += delta_size;
8227 
8228       if (frame_size < 0)
8229         return E_FILE_FORMAT_INVALID;
8230 
8231       if (frame_size > LONG_MAX)
8232         return E_FILE_FORMAT_INVALID;
8233 
8234       curr.len = static_cast<long>(frame_size);
8235       size += curr.len;  // contribution of this frame
8236 
8237       --frame_count;
8238     }
8239 
8240     {
8241       assert(pos <= stop);
8242       assert(pf < pf_end);
8243 
8244       const Frame& prev = *pf++;
8245       assert(prev.len == frame_size);
8246       if (prev.len != frame_size)
8247         return E_FILE_FORMAT_INVALID;
8248 
8249       assert(pf < pf_end);
8250 
8251       Frame& curr = *pf++;
8252       assert(pf == pf_end);
8253 
8254       curr.pos = 0;  // patch later
8255 
8256       const long long total_size = stop - pos;
8257 
8258       if (total_size < size)
8259         return E_FILE_FORMAT_INVALID;
8260 
8261       frame_size = total_size - size;
8262 
8263       if (frame_size > LONG_MAX)
8264         return E_FILE_FORMAT_INVALID;
8265 
8266       curr.len = static_cast<long>(frame_size);
8267     }
8268 
8269     pf = m_frames;
8270     while (pf != pf_end) {
8271       Frame& f = *pf++;
8272       assert((pos + f.len) <= stop);
8273 
8274       f.pos = pos;
8275       pos += f.len;
8276     }
8277 
8278     assert(pos == stop);
8279   }
8280 
8281   return 0;  // success
8282 }
8283 
GetTimeCode(const Cluster * pCluster) const8284 long long Block::GetTimeCode(const Cluster* pCluster) const {
8285   if (pCluster == 0)
8286     return m_timecode;
8287 
8288   const long long tc0 = pCluster->GetTimeCode();
8289   assert(tc0 >= 0);
8290 
8291   const long long tc = tc0 + m_timecode;
8292 
8293   return tc;  // unscaled timecode units
8294 }
8295 
GetTime(const Cluster * pCluster) const8296 long long Block::GetTime(const Cluster* pCluster) const {
8297   assert(pCluster);
8298 
8299   const long long tc = GetTimeCode(pCluster);
8300 
8301   const Segment* const pSegment = pCluster->m_pSegment;
8302   const SegmentInfo* const pInfo = pSegment->GetInfo();
8303   assert(pInfo);
8304 
8305   const long long scale = pInfo->GetTimeCodeScale();
8306   assert(scale >= 1);
8307 
8308   const long long ns = tc * scale;
8309 
8310   return ns;
8311 }
8312 
GetTrackNumber() const8313 long long Block::GetTrackNumber() const { return m_track; }
8314 
IsKey() const8315 bool Block::IsKey() const {
8316   return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
8317 }
8318 
SetKey(bool bKey)8319 void Block::SetKey(bool bKey) {
8320   if (bKey)
8321     m_flags |= static_cast<unsigned char>(1 << 7);
8322   else
8323     m_flags &= 0x7F;
8324 }
8325 
IsInvisible() const8326 bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
8327 
GetLacing() const8328 Block::Lacing Block::GetLacing() const {
8329   const int value = int(m_flags & 0x06) >> 1;
8330   return static_cast<Lacing>(value);
8331 }
8332 
GetFrameCount() const8333 int Block::GetFrameCount() const { return m_frame_count; }
8334 
GetFrame(int idx) const8335 const Block::Frame& Block::GetFrame(int idx) const {
8336   assert(idx >= 0);
8337   assert(idx < m_frame_count);
8338 
8339   const Frame& f = m_frames[idx];
8340   assert(f.pos > 0);
8341   assert(f.len > 0);
8342 
8343   return f;
8344 }
8345 
Read(IMkvReader * pReader,unsigned char * buf) const8346 long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
8347   assert(pReader);
8348   assert(buf);
8349 
8350   const long status = pReader->Read(pos, len, buf);
8351   return status;
8352 }
8353 
GetDiscardPadding() const8354 long long Block::GetDiscardPadding() const { return m_discard_padding; }
8355 
8356 }  // end namespace mkvparser
8357