• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = 30;
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 long size,long long & result)222 long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos,
223                                long long size, 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_pTags(NULL),
611       m_clusters(NULL),
612       m_clusterCount(0),
613       m_clusterPreloadCount(0),
614       m_clusterSize(0) {}
615 
~Segment()616 Segment::~Segment() {
617   const long count = m_clusterCount + m_clusterPreloadCount;
618 
619   Cluster** i = m_clusters;
620   Cluster** j = m_clusters + count;
621 
622   while (i != j) {
623     Cluster* const p = *i++;
624     assert(p);
625 
626     delete p;
627   }
628 
629   delete[] m_clusters;
630 
631   delete m_pTracks;
632   delete m_pInfo;
633   delete m_pCues;
634   delete m_pChapters;
635   delete m_pTags;
636   delete m_pSeekHead;
637 }
638 
CreateInstance(IMkvReader * pReader,long long pos,Segment * & pSegment)639 long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
640                                   Segment*& pSegment) {
641   assert(pReader);
642   assert(pos >= 0);
643 
644   pSegment = NULL;
645 
646   long long total, available;
647 
648   const long status = pReader->Length(&total, &available);
649 
650   if (status < 0)  // error
651     return status;
652 
653   if (available < 0)
654     return -1;
655 
656   if ((total >= 0) && (available > total))
657     return -1;
658 
659   // I would assume that in practice this loop would execute
660   // exactly once, but we allow for other elements (e.g. Void)
661   // to immediately follow the EBML header.  This is fine for
662   // the source filter case (since the entire file is available),
663   // but in the splitter case over a network we should probably
664   // just give up early.  We could for example decide only to
665   // execute this loop a maximum of, say, 10 times.
666   // TODO:
667   // There is an implied "give up early" by only parsing up
668   // to the available limit.  We do do that, but only if the
669   // total file size is unknown.  We could decide to always
670   // use what's available as our limit (irrespective of whether
671   // we happen to know the total file length).  This would have
672   // as its sense "parse this much of the file before giving up",
673   // which a slightly different sense from "try to parse up to
674   // 10 EMBL elements before giving up".
675 
676   for (;;) {
677     if ((total >= 0) && (pos >= total))
678       return E_FILE_FORMAT_INVALID;
679 
680     // Read ID
681     long len;
682     long long result = GetUIntLength(pReader, pos, len);
683 
684     if (result)  // error, or too few available bytes
685       return result;
686 
687     if ((total >= 0) && ((pos + len) > total))
688       return E_FILE_FORMAT_INVALID;
689 
690     if ((pos + len) > available)
691       return pos + len;
692 
693     const long long idpos = pos;
694     const long long id = ReadUInt(pReader, pos, len);
695 
696     if (id < 0)  // error
697       return id;
698 
699     pos += len;  // consume ID
700 
701     // Read Size
702 
703     result = GetUIntLength(pReader, pos, len);
704 
705     if (result)  // error, or too few available bytes
706       return result;
707 
708     if ((total >= 0) && ((pos + len) > total))
709       return E_FILE_FORMAT_INVALID;
710 
711     if ((pos + len) > available)
712       return pos + len;
713 
714     long long size = ReadUInt(pReader, pos, len);
715 
716     if (size < 0)  // error
717       return size;
718 
719     pos += len;  // consume length of size of element
720 
721     // Pos now points to start of payload
722 
723     // Handle "unknown size" for live streaming of webm files.
724     const long long unknown_size = (1LL << (7 * len)) - 1;
725 
726     if (id == 0x08538067) {  // Segment ID
727       if (size == unknown_size)
728         size = -1;
729 
730       else if (total < 0)
731         size = -1;
732 
733       else if ((pos + size) > total)
734         size = -1;
735 
736       pSegment = new (std::nothrow) Segment(pReader, idpos,
737                                             // elem_size
738                                             pos, size);
739 
740       if (pSegment == 0)
741         return -1;  // generic error
742 
743       return 0;  // success
744     }
745 
746     if (size == unknown_size)
747       return E_FILE_FORMAT_INVALID;
748 
749     if ((total >= 0) && ((pos + size) > total))
750       return E_FILE_FORMAT_INVALID;
751 
752     if ((pos + size) > available)
753       return pos + size;
754 
755     pos += size;  // consume payload
756   }
757 }
758 
ParseHeaders()759 long long Segment::ParseHeaders() {
760   // Outermost (level 0) segment object has been constructed,
761   // and pos designates start of payload.  We need to find the
762   // inner (level 1) elements.
763   long long total, available;
764 
765   const int status = m_pReader->Length(&total, &available);
766 
767   if (status < 0)  // error
768     return status;
769 
770   assert((total < 0) || (available <= total));
771 
772   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
773   assert((segment_stop < 0) || (total < 0) || (segment_stop <= total));
774   assert((segment_stop < 0) || (m_pos <= segment_stop));
775 
776   for (;;) {
777     if ((total >= 0) && (m_pos >= total))
778       break;
779 
780     if ((segment_stop >= 0) && (m_pos >= segment_stop))
781       break;
782 
783     long long pos = m_pos;
784     const long long element_start = pos;
785 
786     if ((pos + 1) > available)
787       return (pos + 1);
788 
789     long len;
790     long long result = GetUIntLength(m_pReader, pos, len);
791 
792     if (result < 0)  // error
793       return result;
794 
795     if (result > 0)  // underflow (weird)
796       return (pos + 1);
797 
798     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
799       return E_FILE_FORMAT_INVALID;
800 
801     if ((pos + len) > available)
802       return pos + len;
803 
804     const long long idpos = pos;
805     const long long id = ReadUInt(m_pReader, idpos, len);
806 
807     if (id < 0)  // error
808       return id;
809 
810     if (id == 0x0F43B675)  // Cluster ID
811       break;
812 
813     pos += len;  // consume ID
814 
815     if ((pos + 1) > available)
816       return (pos + 1);
817 
818     // Read Size
819     result = GetUIntLength(m_pReader, pos, len);
820 
821     if (result < 0)  // error
822       return result;
823 
824     if (result > 0)  // underflow (weird)
825       return (pos + 1);
826 
827     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
828       return E_FILE_FORMAT_INVALID;
829 
830     if ((pos + len) > available)
831       return pos + len;
832 
833     const long long size = ReadUInt(m_pReader, pos, len);
834 
835     if (size < 0)  // error
836       return size;
837 
838     pos += len;  // consume length of size of element
839 
840     const long long element_size = size + pos - element_start;
841 
842     // Pos now points to start of payload
843 
844     if ((segment_stop >= 0) && ((pos + size) > segment_stop))
845       return E_FILE_FORMAT_INVALID;
846 
847     // We read EBML elements either in total or nothing at all.
848 
849     if ((pos + size) > available)
850       return pos + size;
851 
852     if (id == 0x0549A966) {  // Segment Info ID
853       if (m_pInfo)
854         return E_FILE_FORMAT_INVALID;
855 
856       m_pInfo = new (std::nothrow)
857           SegmentInfo(this, pos, size, element_start, element_size);
858 
859       if (m_pInfo == NULL)
860         return -1;
861 
862       const long status = m_pInfo->Parse();
863 
864       if (status)
865         return status;
866     } else if (id == 0x0654AE6B) {  // Tracks ID
867       if (m_pTracks)
868         return E_FILE_FORMAT_INVALID;
869 
870       m_pTracks = new (std::nothrow)
871           Tracks(this, pos, size, element_start, element_size);
872 
873       if (m_pTracks == NULL)
874         return -1;
875 
876       const long status = m_pTracks->Parse();
877 
878       if (status)
879         return status;
880     } else if (id == 0x0C53BB6B) {  // Cues ID
881       if (m_pCues == NULL) {
882         m_pCues = new (std::nothrow)
883             Cues(this, pos, size, element_start, element_size);
884 
885         if (m_pCues == NULL)
886           return -1;
887       }
888     } else if (id == 0x014D9B74) {  // SeekHead ID
889       if (m_pSeekHead == NULL) {
890         m_pSeekHead = new (std::nothrow)
891             SeekHead(this, pos, size, element_start, element_size);
892 
893         if (m_pSeekHead == NULL)
894           return -1;
895 
896         const long status = m_pSeekHead->Parse();
897 
898         if (status)
899           return status;
900       }
901     } else if (id == 0x0043A770) {  // Chapters ID
902       if (m_pChapters == NULL) {
903         m_pChapters = new (std::nothrow)
904             Chapters(this, pos, size, element_start, element_size);
905 
906         if (m_pChapters == NULL)
907           return -1;
908 
909         const long status = m_pChapters->Parse();
910 
911         if (status)
912           return status;
913       }
914     } else if (id == 0x0254C367) {  // Tags ID
915       if (m_pTags == NULL) {
916         m_pTags = new (std::nothrow)
917             Tags(this, pos, size, element_start, element_size);
918 
919         if (m_pTags == NULL)
920           return -1;
921 
922         const long status = m_pTags->Parse();
923 
924         if (status)
925           return status;
926       }
927     }
928 
929     m_pos = pos + size;  // consume payload
930   }
931 
932   assert((segment_stop < 0) || (m_pos <= segment_stop));
933 
934   if (m_pInfo == NULL)  // TODO: liberalize this behavior
935     return E_FILE_FORMAT_INVALID;
936 
937   if (m_pTracks == NULL)
938     return E_FILE_FORMAT_INVALID;
939 
940   return 0;  // success
941 }
942 
LoadCluster(long long & pos,long & len)943 long Segment::LoadCluster(long long& pos, long& len) {
944   for (;;) {
945     const long result = DoLoadCluster(pos, len);
946 
947     if (result <= 1)
948       return result;
949   }
950 }
951 
DoLoadCluster(long long & pos,long & len)952 long Segment::DoLoadCluster(long long& pos, long& len) {
953   if (m_pos < 0)
954     return DoLoadClusterUnknownSize(pos, len);
955 
956   long long total, avail;
957 
958   long status = m_pReader->Length(&total, &avail);
959 
960   if (status < 0)  // error
961     return status;
962 
963   assert((total < 0) || (avail <= total));
964 
965   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
966 
967   long long cluster_off = -1;  // offset relative to start of segment
968   long long cluster_size = -1;  // size of cluster payload
969 
970   for (;;) {
971     if ((total >= 0) && (m_pos >= total))
972       return 1;  // no more clusters
973 
974     if ((segment_stop >= 0) && (m_pos >= segment_stop))
975       return 1;  // no more clusters
976 
977     pos = m_pos;
978 
979     // Read ID
980 
981     if ((pos + 1) > avail) {
982       len = 1;
983       return E_BUFFER_NOT_FULL;
984     }
985 
986     long long result = GetUIntLength(m_pReader, pos, len);
987 
988     if (result < 0)  // error
989       return static_cast<long>(result);
990 
991     if (result > 0)  // weird
992       return E_BUFFER_NOT_FULL;
993 
994     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
995       return E_FILE_FORMAT_INVALID;
996 
997     if ((pos + len) > avail)
998       return E_BUFFER_NOT_FULL;
999 
1000     const long long idpos = pos;
1001     const long long id = ReadUInt(m_pReader, idpos, len);
1002 
1003     if (id < 0)  // error (or underflow)
1004       return static_cast<long>(id);
1005 
1006     pos += len;  // consume ID
1007 
1008     // Read Size
1009 
1010     if ((pos + 1) > avail) {
1011       len = 1;
1012       return E_BUFFER_NOT_FULL;
1013     }
1014 
1015     result = GetUIntLength(m_pReader, pos, len);
1016 
1017     if (result < 0)  // error
1018       return static_cast<long>(result);
1019 
1020     if (result > 0)  // weird
1021       return E_BUFFER_NOT_FULL;
1022 
1023     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1024       return E_FILE_FORMAT_INVALID;
1025 
1026     if ((pos + len) > avail)
1027       return E_BUFFER_NOT_FULL;
1028 
1029     const long long size = ReadUInt(m_pReader, pos, len);
1030 
1031     if (size < 0)  // error
1032       return static_cast<long>(size);
1033 
1034     pos += len;  // consume length of size of element
1035 
1036     // pos now points to start of payload
1037 
1038     if (size == 0) {  // weird
1039       m_pos = pos;
1040       continue;
1041     }
1042 
1043     const long long unknown_size = (1LL << (7 * len)) - 1;
1044 
1045     if ((segment_stop >= 0) && (size != unknown_size) &&
1046         ((pos + size) > segment_stop)) {
1047       return E_FILE_FORMAT_INVALID;
1048     }
1049 
1050     if (id == 0x0C53BB6B) {  // Cues ID
1051       if (size == unknown_size)
1052         return E_FILE_FORMAT_INVALID;  // TODO: liberalize
1053 
1054       if (m_pCues == NULL) {
1055         const long long element_size = (pos - idpos) + size;
1056 
1057         m_pCues = new Cues(this, pos, size, idpos, element_size);
1058         assert(m_pCues);  // TODO
1059       }
1060 
1061       m_pos = pos + size;  // consume payload
1062       continue;
1063     }
1064 
1065     if (id != 0x0F43B675) {  // Cluster ID
1066       if (size == unknown_size)
1067         return E_FILE_FORMAT_INVALID;  // TODO: liberalize
1068 
1069       m_pos = pos + size;  // consume payload
1070       continue;
1071     }
1072 
1073     // We have a cluster.
1074 
1075     cluster_off = idpos - m_start;  // relative pos
1076 
1077     if (size != unknown_size)
1078       cluster_size = size;
1079 
1080     break;
1081   }
1082 
1083   assert(cluster_off >= 0);  // have cluster
1084 
1085   long long pos_;
1086   long len_;
1087 
1088   status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_);
1089 
1090   if (status < 0) {  // error, or underflow
1091     pos = pos_;
1092     len = len_;
1093 
1094     return status;
1095   }
1096 
1097   // status == 0 means "no block entries found"
1098   // status > 0 means "found at least one block entry"
1099 
1100   // TODO:
1101   // The issue here is that the segment increments its own
1102   // pos ptr past the most recent cluster parsed, and then
1103   // starts from there to parse the next cluster.  If we
1104   // don't know the size of the current cluster, then we
1105   // must either parse its payload (as we do below), looking
1106   // for the cluster (or cues) ID to terminate the parse.
1107   // This isn't really what we want: rather, we really need
1108   // a way to create the curr cluster object immediately.
1109   // The pity is that cluster::parse can determine its own
1110   // boundary, and we largely duplicate that same logic here.
1111   //
1112   // Maybe we need to get rid of our look-ahead preloading
1113   // in source::parse???
1114   //
1115   // As we're parsing the blocks in the curr cluster
1116   //(in cluster::parse), we should have some way to signal
1117   // to the segment that we have determined the boundary,
1118   // so it can adjust its own segment::m_pos member.
1119   //
1120   // The problem is that we're asserting in asyncreadinit,
1121   // because we adjust the pos down to the curr seek pos,
1122   // and the resulting adjusted len is > 2GB.  I'm suspicious
1123   // that this is even correct, but even if it is, we can't
1124   // be loading that much data in the cache anyway.
1125 
1126   const long idx = m_clusterCount;
1127 
1128   if (m_clusterPreloadCount > 0) {
1129     assert(idx < m_clusterSize);
1130 
1131     Cluster* const pCluster = m_clusters[idx];
1132     assert(pCluster);
1133     assert(pCluster->m_index < 0);
1134 
1135     const long long off = pCluster->GetPosition();
1136     assert(off >= 0);
1137 
1138     if (off == cluster_off) {  // preloaded already
1139       if (status == 0)  // no entries found
1140         return E_FILE_FORMAT_INVALID;
1141 
1142       if (cluster_size >= 0)
1143         pos += cluster_size;
1144       else {
1145         const long long element_size = pCluster->GetElementSize();
1146 
1147         if (element_size <= 0)
1148           return E_FILE_FORMAT_INVALID;  // TODO: handle this case
1149 
1150         pos = pCluster->m_element_start + element_size;
1151       }
1152 
1153       pCluster->m_index = idx;  // move from preloaded to loaded
1154       ++m_clusterCount;
1155       --m_clusterPreloadCount;
1156 
1157       m_pos = pos;  // consume payload
1158       assert((segment_stop < 0) || (m_pos <= segment_stop));
1159 
1160       return 0;  // success
1161     }
1162   }
1163 
1164   if (status == 0) {  // no entries found
1165     if (cluster_size >= 0)
1166       pos += cluster_size;
1167 
1168     if ((total >= 0) && (pos >= total)) {
1169       m_pos = total;
1170       return 1;  // no more clusters
1171     }
1172 
1173     if ((segment_stop >= 0) && (pos >= segment_stop)) {
1174       m_pos = segment_stop;
1175       return 1;  // no more clusters
1176     }
1177 
1178     m_pos = pos;
1179     return 2;  // try again
1180   }
1181 
1182   // status > 0 means we have an entry
1183 
1184   Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
1185   // element_size);
1186   assert(pCluster);
1187 
1188   AppendCluster(pCluster);
1189   assert(m_clusters);
1190   assert(idx < m_clusterSize);
1191   assert(m_clusters[idx] == pCluster);
1192 
1193   if (cluster_size >= 0) {
1194     pos += cluster_size;
1195 
1196     m_pos = pos;
1197     assert((segment_stop < 0) || (m_pos <= segment_stop));
1198 
1199     return 0;
1200   }
1201 
1202   m_pUnknownSize = pCluster;
1203   m_pos = -pos;
1204 
1205   return 0;  // partial success, since we have a new cluster
1206 
1207   // status == 0 means "no block entries found"
1208   // pos designates start of payload
1209   // m_pos has NOT been adjusted yet (in case we need to come back here)
1210 }
1211 
DoLoadClusterUnknownSize(long long & pos,long & len)1212 long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
1213   assert(m_pos < 0);
1214   assert(m_pUnknownSize);
1215 
1216   const long status = m_pUnknownSize->Parse(pos, len);
1217 
1218   if (status < 0)  // error or underflow
1219     return status;
1220 
1221   if (status == 0)  // parsed a block
1222     return 2;  // continue parsing
1223 
1224   assert(status > 0);  // nothing left to parse of this cluster
1225 
1226   const long long start = m_pUnknownSize->m_element_start;
1227 
1228   const long long size = m_pUnknownSize->GetElementSize();
1229   assert(size >= 0);
1230 
1231   pos = start + size;
1232   m_pos = pos;
1233 
1234   m_pUnknownSize = 0;
1235 
1236   return 2;  // continue parsing
1237 }
1238 
AppendCluster(Cluster * pCluster)1239 void Segment::AppendCluster(Cluster* pCluster) {
1240   assert(pCluster);
1241   assert(pCluster->m_index >= 0);
1242 
1243   const long count = m_clusterCount + m_clusterPreloadCount;
1244 
1245   long& size = m_clusterSize;
1246   assert(size >= count);
1247 
1248   const long idx = pCluster->m_index;
1249   assert(idx == m_clusterCount);
1250 
1251   if (count >= size) {
1252     const long n = (size <= 0) ? 2048 : 2 * size;
1253 
1254     Cluster** const qq = new Cluster*[n];
1255     Cluster** q = qq;
1256 
1257     Cluster** p = m_clusters;
1258     Cluster** const pp = p + count;
1259 
1260     while (p != pp)
1261       *q++ = *p++;
1262 
1263     delete[] m_clusters;
1264 
1265     m_clusters = qq;
1266     size = n;
1267   }
1268 
1269   if (m_clusterPreloadCount > 0) {
1270     assert(m_clusters);
1271 
1272     Cluster** const p = m_clusters + m_clusterCount;
1273     assert(*p);
1274     assert((*p)->m_index < 0);
1275 
1276     Cluster** q = p + m_clusterPreloadCount;
1277     assert(q < (m_clusters + size));
1278 
1279     for (;;) {
1280       Cluster** const qq = q - 1;
1281       assert((*qq)->m_index < 0);
1282 
1283       *q = *qq;
1284       q = qq;
1285 
1286       if (q == p)
1287         break;
1288     }
1289   }
1290 
1291   m_clusters[idx] = pCluster;
1292   ++m_clusterCount;
1293 }
1294 
PreloadCluster(Cluster * pCluster,ptrdiff_t idx)1295 void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
1296   assert(pCluster);
1297   assert(pCluster->m_index < 0);
1298   assert(idx >= m_clusterCount);
1299 
1300   const long count = m_clusterCount + m_clusterPreloadCount;
1301 
1302   long& size = m_clusterSize;
1303   assert(size >= count);
1304 
1305   if (count >= size) {
1306     const long n = (size <= 0) ? 2048 : 2 * size;
1307 
1308     Cluster** const qq = new Cluster*[n];
1309     Cluster** q = qq;
1310 
1311     Cluster** p = m_clusters;
1312     Cluster** const pp = p + count;
1313 
1314     while (p != pp)
1315       *q++ = *p++;
1316 
1317     delete[] m_clusters;
1318 
1319     m_clusters = qq;
1320     size = n;
1321   }
1322 
1323   assert(m_clusters);
1324 
1325   Cluster** const p = m_clusters + idx;
1326 
1327   Cluster** q = m_clusters + count;
1328   assert(q >= p);
1329   assert(q < (m_clusters + size));
1330 
1331   while (q > p) {
1332     Cluster** const qq = q - 1;
1333     assert((*qq)->m_index < 0);
1334 
1335     *q = *qq;
1336     q = qq;
1337   }
1338 
1339   m_clusters[idx] = pCluster;
1340   ++m_clusterPreloadCount;
1341 }
1342 
Load()1343 long Segment::Load() {
1344   assert(m_clusters == NULL);
1345   assert(m_clusterSize == 0);
1346   assert(m_clusterCount == 0);
1347   // assert(m_size >= 0);
1348 
1349   // Outermost (level 0) segment object has been constructed,
1350   // and pos designates start of payload.  We need to find the
1351   // inner (level 1) elements.
1352 
1353   const long long header_status = ParseHeaders();
1354 
1355   if (header_status < 0)  // error
1356     return static_cast<long>(header_status);
1357 
1358   if (header_status > 0)  // underflow
1359     return E_BUFFER_NOT_FULL;
1360 
1361   assert(m_pInfo);
1362   assert(m_pTracks);
1363 
1364   for (;;) {
1365     const int status = LoadCluster();
1366 
1367     if (status < 0)  // error
1368       return status;
1369 
1370     if (status >= 1)  // no more clusters
1371       return 0;
1372   }
1373 }
1374 
SeekHead(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)1375 SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
1376                    long long element_start, long long element_size)
1377     : m_pSegment(pSegment),
1378       m_start(start),
1379       m_size(size_),
1380       m_element_start(element_start),
1381       m_element_size(element_size),
1382       m_entries(0),
1383       m_entry_count(0),
1384       m_void_elements(0),
1385       m_void_element_count(0) {}
1386 
~SeekHead()1387 SeekHead::~SeekHead() {
1388   delete[] m_entries;
1389   delete[] m_void_elements;
1390 }
1391 
Parse()1392 long SeekHead::Parse() {
1393   IMkvReader* const pReader = m_pSegment->m_pReader;
1394 
1395   long long pos = m_start;
1396   const long long stop = m_start + m_size;
1397 
1398   // first count the seek head entries
1399 
1400   int entry_count = 0;
1401   int void_element_count = 0;
1402 
1403   while (pos < stop) {
1404     long long id, size;
1405 
1406     const long status = ParseElementHeader(pReader, pos, stop, id, size);
1407 
1408     if (status < 0)  // error
1409       return status;
1410 
1411     if (id == 0x0DBB)  // SeekEntry ID
1412       ++entry_count;
1413     else if (id == 0x6C)  // Void ID
1414       ++void_element_count;
1415 
1416     pos += size;  // consume payload
1417     assert(pos <= stop);
1418   }
1419 
1420   assert(pos == stop);
1421 
1422   m_entries = new (std::nothrow) Entry[entry_count];
1423 
1424   if (m_entries == NULL)
1425     return -1;
1426 
1427   m_void_elements = new (std::nothrow) VoidElement[void_element_count];
1428 
1429   if (m_void_elements == NULL)
1430     return -1;
1431 
1432   // now parse the entries and void elements
1433 
1434   Entry* pEntry = m_entries;
1435   VoidElement* pVoidElement = m_void_elements;
1436 
1437   pos = m_start;
1438 
1439   while (pos < stop) {
1440     const long long idpos = pos;
1441 
1442     long long id, size;
1443 
1444     const long status = ParseElementHeader(pReader, pos, stop, id, size);
1445 
1446     if (status < 0)  // error
1447       return status;
1448 
1449     if (id == 0x0DBB) {  // SeekEntry ID
1450       if (ParseEntry(pReader, pos, size, pEntry)) {
1451         Entry& e = *pEntry++;
1452 
1453         e.element_start = idpos;
1454         e.element_size = (pos + size) - idpos;
1455       }
1456     } else if (id == 0x6C) {  // Void ID
1457       VoidElement& e = *pVoidElement++;
1458 
1459       e.element_start = idpos;
1460       e.element_size = (pos + size) - idpos;
1461     }
1462 
1463     pos += size;  // consume payload
1464     assert(pos <= stop);
1465   }
1466 
1467   assert(pos == stop);
1468 
1469   ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
1470   assert(count_ >= 0);
1471   assert(count_ <= entry_count);
1472 
1473   m_entry_count = static_cast<int>(count_);
1474 
1475   count_ = ptrdiff_t(pVoidElement - m_void_elements);
1476   assert(count_ >= 0);
1477   assert(count_ <= void_element_count);
1478 
1479   m_void_element_count = static_cast<int>(count_);
1480 
1481   return 0;
1482 }
1483 
GetCount() const1484 int SeekHead::GetCount() const { return m_entry_count; }
1485 
GetEntry(int idx) const1486 const SeekHead::Entry* SeekHead::GetEntry(int idx) const {
1487   if (idx < 0)
1488     return 0;
1489 
1490   if (idx >= m_entry_count)
1491     return 0;
1492 
1493   return m_entries + idx;
1494 }
1495 
GetVoidElementCount() const1496 int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
1497 
GetVoidElement(int idx) const1498 const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const {
1499   if (idx < 0)
1500     return 0;
1501 
1502   if (idx >= m_void_element_count)
1503     return 0;
1504 
1505   return m_void_elements + idx;
1506 }
1507 
ParseCues(long long off,long long & pos,long & len)1508 long Segment::ParseCues(long long off, long long& pos, long& len) {
1509   if (m_pCues)
1510     return 0;  // success
1511 
1512   if (off < 0)
1513     return -1;
1514 
1515   long long total, avail;
1516 
1517   const int status = m_pReader->Length(&total, &avail);
1518 
1519   if (status < 0)  // error
1520     return status;
1521 
1522   assert((total < 0) || (avail <= total));
1523 
1524   pos = m_start + off;
1525 
1526   if ((total < 0) || (pos >= total))
1527     return 1;  // don't bother parsing cues
1528 
1529   const long long element_start = pos;
1530   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1531 
1532   if ((pos + 1) > avail) {
1533     len = 1;
1534     return E_BUFFER_NOT_FULL;
1535   }
1536 
1537   long long result = GetUIntLength(m_pReader, pos, len);
1538 
1539   if (result < 0)  // error
1540     return static_cast<long>(result);
1541 
1542   if (result > 0)  // underflow (weird)
1543   {
1544     len = 1;
1545     return E_BUFFER_NOT_FULL;
1546   }
1547 
1548   if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1549     return E_FILE_FORMAT_INVALID;
1550 
1551   if ((pos + len) > avail)
1552     return E_BUFFER_NOT_FULL;
1553 
1554   const long long idpos = pos;
1555 
1556   const long long id = ReadUInt(m_pReader, idpos, len);
1557 
1558   if (id != 0x0C53BB6B)  // Cues ID
1559     return E_FILE_FORMAT_INVALID;
1560 
1561   pos += len;  // consume ID
1562   assert((segment_stop < 0) || (pos <= segment_stop));
1563 
1564   // Read Size
1565 
1566   if ((pos + 1) > avail) {
1567     len = 1;
1568     return E_BUFFER_NOT_FULL;
1569   }
1570 
1571   result = GetUIntLength(m_pReader, pos, len);
1572 
1573   if (result < 0)  // error
1574     return static_cast<long>(result);
1575 
1576   if (result > 0)  // underflow (weird)
1577   {
1578     len = 1;
1579     return E_BUFFER_NOT_FULL;
1580   }
1581 
1582   if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1583     return E_FILE_FORMAT_INVALID;
1584 
1585   if ((pos + len) > avail)
1586     return E_BUFFER_NOT_FULL;
1587 
1588   const long long size = ReadUInt(m_pReader, pos, len);
1589 
1590   if (size < 0)  // error
1591     return static_cast<long>(size);
1592 
1593   if (size == 0)  // weird, although technically not illegal
1594     return 1;  // done
1595 
1596   pos += len;  // consume length of size of element
1597   assert((segment_stop < 0) || (pos <= segment_stop));
1598 
1599   // Pos now points to start of payload
1600 
1601   const long long element_stop = pos + size;
1602 
1603   if ((segment_stop >= 0) && (element_stop > segment_stop))
1604     return E_FILE_FORMAT_INVALID;
1605 
1606   if ((total >= 0) && (element_stop > total))
1607     return 1;  // don't bother parsing anymore
1608 
1609   len = static_cast<long>(size);
1610 
1611   if (element_stop > avail)
1612     return E_BUFFER_NOT_FULL;
1613 
1614   const long long element_size = element_stop - element_start;
1615 
1616   m_pCues =
1617       new (std::nothrow) Cues(this, pos, size, element_start, element_size);
1618   assert(m_pCues);  // TODO
1619 
1620   return 0;  // success
1621 }
1622 
ParseEntry(IMkvReader * pReader,long long start,long long size_,Entry * pEntry)1623 bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
1624                           Entry* pEntry) {
1625   if (size_ <= 0)
1626     return false;
1627 
1628   long long pos = start;
1629   const long long stop = start + size_;
1630 
1631   long len;
1632 
1633   // parse the container for the level-1 element ID
1634 
1635   const long long seekIdId = ReadUInt(pReader, pos, len);
1636   // seekIdId;
1637 
1638   if (seekIdId != 0x13AB)  // SeekID ID
1639     return false;
1640 
1641   if ((pos + len) > stop)
1642     return false;
1643 
1644   pos += len;  // consume SeekID id
1645 
1646   const long long seekIdSize = ReadUInt(pReader, pos, len);
1647 
1648   if (seekIdSize <= 0)
1649     return false;
1650 
1651   if ((pos + len) > stop)
1652     return false;
1653 
1654   pos += len;  // consume size of field
1655 
1656   if ((pos + seekIdSize) > stop)
1657     return false;
1658 
1659   // Note that the SeekId payload really is serialized
1660   // as a "Matroska integer", not as a plain binary value.
1661   // In fact, Matroska requires that ID values in the
1662   // stream exactly match the binary representation as listed
1663   // in the Matroska specification.
1664   //
1665   // This parser is more liberal, and permits IDs to have
1666   // any width.  (This could make the representation in the stream
1667   // different from what's in the spec, but it doesn't matter here,
1668   // since we always normalize "Matroska integer" values.)
1669 
1670   pEntry->id = ReadUInt(pReader, pos, len);  // payload
1671 
1672   if (pEntry->id <= 0)
1673     return false;
1674 
1675   if (len != seekIdSize)
1676     return false;
1677 
1678   pos += seekIdSize;  // consume SeekID payload
1679 
1680   const long long seekPosId = ReadUInt(pReader, pos, len);
1681 
1682   if (seekPosId != 0x13AC)  // SeekPos ID
1683     return false;
1684 
1685   if ((pos + len) > stop)
1686     return false;
1687 
1688   pos += len;  // consume id
1689 
1690   const long long seekPosSize = ReadUInt(pReader, pos, len);
1691 
1692   if (seekPosSize <= 0)
1693     return false;
1694 
1695   if ((pos + len) > stop)
1696     return false;
1697 
1698   pos += len;  // consume size
1699 
1700   if ((pos + seekPosSize) > stop)
1701     return false;
1702 
1703   pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
1704 
1705   if (pEntry->pos < 0)
1706     return false;
1707 
1708   pos += seekPosSize;  // consume payload
1709 
1710   if (pos != stop)
1711     return false;
1712 
1713   return true;
1714 }
1715 
Cues(Segment * pSegment,long long start_,long long size_,long long element_start,long long element_size)1716 Cues::Cues(Segment* pSegment, long long start_, long long size_,
1717            long long element_start, long long element_size)
1718     : m_pSegment(pSegment),
1719       m_start(start_),
1720       m_size(size_),
1721       m_element_start(element_start),
1722       m_element_size(element_size),
1723       m_cue_points(NULL),
1724       m_count(0),
1725       m_preload_count(0),
1726       m_pos(start_) {}
1727 
~Cues()1728 Cues::~Cues() {
1729   const long n = m_count + m_preload_count;
1730 
1731   CuePoint** p = m_cue_points;
1732   CuePoint** const q = p + n;
1733 
1734   while (p != q) {
1735     CuePoint* const pCP = *p++;
1736     assert(pCP);
1737 
1738     delete pCP;
1739   }
1740 
1741   delete[] m_cue_points;
1742 }
1743 
GetCount() const1744 long Cues::GetCount() const {
1745   if (m_cue_points == NULL)
1746     return -1;
1747 
1748   return m_count;  // TODO: really ignore preload count?
1749 }
1750 
DoneParsing() const1751 bool Cues::DoneParsing() const {
1752   const long long stop = m_start + m_size;
1753   return (m_pos >= stop);
1754 }
1755 
Init() const1756 bool Cues::Init() const {
1757   if (m_cue_points)
1758     return true;
1759 
1760   assert(m_count == 0);
1761   assert(m_preload_count == 0);
1762 
1763   IMkvReader* const pReader = m_pSegment->m_pReader;
1764 
1765   const long long stop = m_start + m_size;
1766   long long pos = m_start;
1767 
1768   long cue_points_size = 0;
1769 
1770   while (pos < stop) {
1771     const long long idpos = pos;
1772 
1773     long len;
1774 
1775     const long long id = ReadUInt(pReader, pos, len);
1776     if (id < 0 || (pos + len) > stop) {
1777       return false;
1778     }
1779 
1780     pos += len;  // consume ID
1781 
1782     const long long size = ReadUInt(pReader, pos, len);
1783     if (size < 0 || (pos + len > stop)) {
1784       return false;
1785     }
1786 
1787     pos += len;  // consume Size field
1788     if (pos + size > stop) {
1789       return false;
1790     }
1791 
1792     if (id == 0x3B)  // CuePoint ID
1793       PreloadCuePoint(cue_points_size, idpos);
1794 
1795     pos += size;  // skip payload
1796   }
1797   return true;
1798 }
1799 
PreloadCuePoint(long & cue_points_size,long long pos) const1800 void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
1801   assert(m_count == 0);
1802 
1803   if (m_preload_count >= cue_points_size) {
1804     const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
1805 
1806     CuePoint** const qq = new CuePoint*[n];
1807     CuePoint** q = qq;  // beginning of target
1808 
1809     CuePoint** p = m_cue_points;  // beginning of source
1810     CuePoint** const pp = p + m_preload_count;  // end of source
1811 
1812     while (p != pp)
1813       *q++ = *p++;
1814 
1815     delete[] m_cue_points;
1816 
1817     m_cue_points = qq;
1818     cue_points_size = n;
1819   }
1820 
1821   CuePoint* const pCP = new CuePoint(m_preload_count, pos);
1822   m_cue_points[m_preload_count++] = pCP;
1823 }
1824 
LoadCuePoint() const1825 bool Cues::LoadCuePoint() const {
1826   // odbgstream os;
1827   // os << "Cues::LoadCuePoint" << endl;
1828 
1829   const long long stop = m_start + m_size;
1830 
1831   if (m_pos >= stop)
1832     return false;  // nothing else to do
1833 
1834   if (!Init()) {
1835     m_pos = stop;
1836     return false;
1837   }
1838 
1839   IMkvReader* const pReader = m_pSegment->m_pReader;
1840 
1841   while (m_pos < stop) {
1842     const long long idpos = m_pos;
1843 
1844     long len;
1845 
1846     const long long id = ReadUInt(pReader, m_pos, len);
1847     assert(id >= 0);  // TODO
1848     assert((m_pos + len) <= stop);
1849 
1850     m_pos += len;  // consume ID
1851 
1852     const long long size = ReadUInt(pReader, m_pos, len);
1853     assert(size >= 0);
1854     assert((m_pos + len) <= stop);
1855 
1856     m_pos += len;  // consume Size field
1857     assert((m_pos + size) <= stop);
1858 
1859     if (id != 0x3B) {  // CuePoint ID
1860       m_pos += size;  // consume payload
1861       assert(m_pos <= stop);
1862 
1863       continue;
1864     }
1865 
1866     assert(m_preload_count > 0);
1867 
1868     CuePoint* const pCP = m_cue_points[m_count];
1869     assert(pCP);
1870     assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos));
1871     if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos))
1872       return false;
1873 
1874     if (!pCP->Load(pReader)) {
1875       m_pos = stop;
1876       return false;
1877     }
1878     ++m_count;
1879     --m_preload_count;
1880 
1881     m_pos += size;  // consume payload
1882     assert(m_pos <= stop);
1883 
1884     return true;  // yes, we loaded a cue point
1885   }
1886 
1887   // return (m_pos < stop);
1888   return false;  // no, we did not load a cue point
1889 }
1890 
Find(long long time_ns,const Track * pTrack,const CuePoint * & pCP,const CuePoint::TrackPosition * & pTP) const1891 bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
1892                 const CuePoint::TrackPosition*& pTP) const {
1893   assert(time_ns >= 0);
1894   assert(pTrack);
1895 
1896   if (m_cue_points == NULL)
1897     return false;
1898 
1899   if (m_count == 0)
1900     return false;
1901 
1902   CuePoint** const ii = m_cue_points;
1903   CuePoint** i = ii;
1904 
1905   CuePoint** const jj = ii + m_count;
1906   CuePoint** j = jj;
1907 
1908   pCP = *i;
1909   assert(pCP);
1910 
1911   if (time_ns <= pCP->GetTime(m_pSegment)) {
1912     pTP = pCP->Find(pTrack);
1913     return (pTP != NULL);
1914   }
1915 
1916   while (i < j) {
1917     // INVARIANT:
1918     //[ii, i) <= time_ns
1919     //[i, j)  ?
1920     //[j, jj) > time_ns
1921 
1922     CuePoint** const k = i + (j - i) / 2;
1923     assert(k < jj);
1924 
1925     CuePoint* const pCP = *k;
1926     assert(pCP);
1927 
1928     const long long t = pCP->GetTime(m_pSegment);
1929 
1930     if (t <= time_ns)
1931       i = k + 1;
1932     else
1933       j = k;
1934 
1935     assert(i <= j);
1936   }
1937 
1938   assert(i == j);
1939   assert(i <= jj);
1940   assert(i > ii);
1941 
1942   pCP = *--i;
1943   assert(pCP);
1944   assert(pCP->GetTime(m_pSegment) <= time_ns);
1945 
1946   // TODO: here and elsewhere, it's probably not correct to search
1947   // for the cue point with this time, and then search for a matching
1948   // track.  In principle, the matching track could be on some earlier
1949   // cue point, and with our current algorithm, we'd miss it.  To make
1950   // this bullet-proof, we'd need to create a secondary structure,
1951   // with a list of cue points that apply to a track, and then search
1952   // that track-based structure for a matching cue point.
1953 
1954   pTP = pCP->Find(pTrack);
1955   return (pTP != NULL);
1956 }
1957 
GetFirst() const1958 const CuePoint* Cues::GetFirst() const {
1959   if (m_cue_points == NULL)
1960     return NULL;
1961 
1962   if (m_count == 0)
1963     return NULL;
1964 
1965   CuePoint* const* const pp = m_cue_points;
1966   assert(pp);
1967 
1968   CuePoint* const pCP = pp[0];
1969   assert(pCP);
1970   assert(pCP->GetTimeCode() >= 0);
1971 
1972   return pCP;
1973 }
1974 
GetLast() const1975 const CuePoint* Cues::GetLast() const {
1976   if (m_cue_points == NULL)
1977     return NULL;
1978 
1979   if (m_count <= 0)
1980     return NULL;
1981 
1982   const long index = m_count - 1;
1983 
1984   CuePoint* const* const pp = m_cue_points;
1985   assert(pp);
1986 
1987   CuePoint* const pCP = pp[index];
1988   assert(pCP);
1989   assert(pCP->GetTimeCode() >= 0);
1990 
1991   return pCP;
1992 }
1993 
GetNext(const CuePoint * pCurr) const1994 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
1995   if (pCurr == NULL)
1996     return NULL;
1997 
1998   assert(pCurr->GetTimeCode() >= 0);
1999   assert(m_cue_points);
2000   assert(m_count >= 1);
2001 
2002   long index = pCurr->m_index;
2003   assert(index < m_count);
2004 
2005   CuePoint* const* const pp = m_cue_points;
2006   assert(pp);
2007   assert(pp[index] == pCurr);
2008 
2009   ++index;
2010 
2011   if (index >= m_count)
2012     return NULL;
2013 
2014   CuePoint* const pNext = pp[index];
2015   assert(pNext);
2016   assert(pNext->GetTimeCode() >= 0);
2017 
2018   return pNext;
2019 }
2020 
GetBlock(const CuePoint * pCP,const CuePoint::TrackPosition * pTP) const2021 const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
2022                                  const CuePoint::TrackPosition* pTP) const {
2023   if (pCP == NULL)
2024     return NULL;
2025 
2026   if (pTP == NULL)
2027     return NULL;
2028 
2029   return m_pSegment->GetBlock(*pCP, *pTP);
2030 }
2031 
GetBlock(const CuePoint & cp,const CuePoint::TrackPosition & tp)2032 const BlockEntry* Segment::GetBlock(const CuePoint& cp,
2033                                     const CuePoint::TrackPosition& tp) {
2034   Cluster** const ii = m_clusters;
2035   Cluster** i = ii;
2036 
2037   const long count = m_clusterCount + m_clusterPreloadCount;
2038 
2039   Cluster** const jj = ii + count;
2040   Cluster** j = jj;
2041 
2042   while (i < j) {
2043     // INVARIANT:
2044     //[ii, i) < pTP->m_pos
2045     //[i, j) ?
2046     //[j, jj)  > pTP->m_pos
2047 
2048     Cluster** const k = i + (j - i) / 2;
2049     assert(k < jj);
2050 
2051     Cluster* const pCluster = *k;
2052     assert(pCluster);
2053 
2054     // const long long pos_ = pCluster->m_pos;
2055     // assert(pos_);
2056     // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2057 
2058     const long long pos = pCluster->GetPosition();
2059     assert(pos >= 0);
2060 
2061     if (pos < tp.m_pos)
2062       i = k + 1;
2063     else if (pos > tp.m_pos)
2064       j = k;
2065     else
2066       return pCluster->GetEntry(cp, tp);
2067   }
2068 
2069   assert(i == j);
2070   // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2071 
2072   Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos);  //, -1);
2073   assert(pCluster);
2074 
2075   const ptrdiff_t idx = i - m_clusters;
2076 
2077   PreloadCluster(pCluster, idx);
2078   assert(m_clusters);
2079   assert(m_clusterPreloadCount > 0);
2080   assert(m_clusters[idx] == pCluster);
2081 
2082   return pCluster->GetEntry(cp, tp);
2083 }
2084 
FindOrPreloadCluster(long long requested_pos)2085 const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
2086   if (requested_pos < 0)
2087     return 0;
2088 
2089   Cluster** const ii = m_clusters;
2090   Cluster** i = ii;
2091 
2092   const long count = m_clusterCount + m_clusterPreloadCount;
2093 
2094   Cluster** const jj = ii + count;
2095   Cluster** j = jj;
2096 
2097   while (i < j) {
2098     // INVARIANT:
2099     //[ii, i) < pTP->m_pos
2100     //[i, j) ?
2101     //[j, jj)  > pTP->m_pos
2102 
2103     Cluster** const k = i + (j - i) / 2;
2104     assert(k < jj);
2105 
2106     Cluster* const pCluster = *k;
2107     assert(pCluster);
2108 
2109     // const long long pos_ = pCluster->m_pos;
2110     // assert(pos_);
2111     // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2112 
2113     const long long pos = pCluster->GetPosition();
2114     assert(pos >= 0);
2115 
2116     if (pos < requested_pos)
2117       i = k + 1;
2118     else if (pos > requested_pos)
2119       j = k;
2120     else
2121       return pCluster;
2122   }
2123 
2124   assert(i == j);
2125   // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2126 
2127   Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
2128   //-1);
2129   assert(pCluster);
2130 
2131   const ptrdiff_t idx = i - m_clusters;
2132 
2133   PreloadCluster(pCluster, idx);
2134   assert(m_clusters);
2135   assert(m_clusterPreloadCount > 0);
2136   assert(m_clusters[idx] == pCluster);
2137 
2138   return pCluster;
2139 }
2140 
CuePoint(long idx,long long pos)2141 CuePoint::CuePoint(long idx, long long pos)
2142     : m_element_start(0),
2143       m_element_size(0),
2144       m_index(idx),
2145       m_timecode(-1 * pos),
2146       m_track_positions(NULL),
2147       m_track_positions_count(0) {
2148   assert(pos > 0);
2149 }
2150 
~CuePoint()2151 CuePoint::~CuePoint() { delete[] m_track_positions; }
2152 
Load(IMkvReader * pReader)2153 bool CuePoint::Load(IMkvReader* pReader) {
2154   // odbgstream os;
2155   // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
2156 
2157   if (m_timecode >= 0)  // already loaded
2158     return true;
2159 
2160   assert(m_track_positions == NULL);
2161   assert(m_track_positions_count == 0);
2162 
2163   long long pos_ = -m_timecode;
2164   const long long element_start = pos_;
2165 
2166   long long stop;
2167 
2168   {
2169     long len;
2170 
2171     const long long id = ReadUInt(pReader, pos_, len);
2172     assert(id == 0x3B);  // CuePoint ID
2173     if (id != 0x3B)
2174       return false;
2175 
2176     pos_ += len;  // consume ID
2177 
2178     const long long size = ReadUInt(pReader, pos_, len);
2179     assert(size >= 0);
2180 
2181     pos_ += len;  // consume Size field
2182     // pos_ now points to start of payload
2183 
2184     stop = pos_ + size;
2185   }
2186 
2187   const long long element_size = stop - element_start;
2188 
2189   long long pos = pos_;
2190 
2191   // First count number of track positions
2192 
2193   while (pos < stop) {
2194     long len;
2195 
2196     const long long id = ReadUInt(pReader, pos, len);
2197     if ((id < 0) || (pos + len > stop)) {
2198       return false;
2199     }
2200 
2201     pos += len;  // consume ID
2202 
2203     const long long size = ReadUInt(pReader, pos, len);
2204     if ((size < 0) || (pos + len > stop)) {
2205       return false;
2206     }
2207 
2208     pos += len;  // consume Size field
2209     if ((pos + size) > stop) {
2210       return false;
2211     }
2212 
2213     if (id == 0x33)  // CueTime ID
2214       m_timecode = UnserializeUInt(pReader, pos, size);
2215 
2216     else if (id == 0x37)  // CueTrackPosition(s) ID
2217       ++m_track_positions_count;
2218 
2219     pos += size;  // consume payload
2220   }
2221 
2222   if (m_timecode < 0 || m_track_positions_count <= 0) {
2223     return false;
2224   }
2225 
2226   // os << "CuePoint::Load(cont'd): idpos=" << idpos
2227   //   << " timecode=" << m_timecode
2228   //   << endl;
2229 
2230   m_track_positions = new TrackPosition[m_track_positions_count];
2231 
2232   // Now parse track positions
2233 
2234   TrackPosition* p = m_track_positions;
2235   pos = pos_;
2236 
2237   while (pos < stop) {
2238     long len;
2239 
2240     const long long id = ReadUInt(pReader, pos, len);
2241     assert(id >= 0);
2242     assert((pos + len) <= stop);
2243 
2244     pos += len;  // consume ID
2245 
2246     const long long size = ReadUInt(pReader, pos, len);
2247     assert(size >= 0);
2248     assert((pos + len) <= stop);
2249 
2250     pos += len;  // consume Size field
2251     assert((pos + size) <= stop);
2252 
2253     if (id == 0x37) {  // CueTrackPosition(s) ID
2254       TrackPosition& tp = *p++;
2255       if (!tp.Parse(pReader, pos, size)) {
2256         return false;
2257       }
2258     }
2259 
2260     pos += size;  // consume payload
2261     assert(pos <= stop);
2262   }
2263 
2264   assert(size_t(p - m_track_positions) == m_track_positions_count);
2265 
2266   m_element_start = element_start;
2267   m_element_size = element_size;
2268 
2269   return true;
2270 }
2271 
Parse(IMkvReader * pReader,long long start_,long long size_)2272 bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
2273                                     long long size_) {
2274   const long long stop = start_ + size_;
2275   long long pos = start_;
2276 
2277   m_track = -1;
2278   m_pos = -1;
2279   m_block = 1;  // default
2280 
2281   while (pos < stop) {
2282     long len;
2283 
2284     const long long id = ReadUInt(pReader, pos, len);
2285     if ((id < 0) || ((pos + len) > stop)) {
2286       return false;
2287     }
2288 
2289     pos += len;  // consume ID
2290 
2291     const long long size = ReadUInt(pReader, pos, len);
2292     if ((size < 0) || ((pos + len) > stop)) {
2293       return false;
2294     }
2295 
2296     pos += len;  // consume Size field
2297     if ((pos + size) > stop) {
2298       return false;
2299     }
2300 
2301     if (id == 0x77)  // CueTrack ID
2302       m_track = UnserializeUInt(pReader, pos, size);
2303 
2304     else if (id == 0x71)  // CueClusterPos ID
2305       m_pos = UnserializeUInt(pReader, pos, size);
2306 
2307     else if (id == 0x1378)  // CueBlockNumber
2308       m_block = UnserializeUInt(pReader, pos, size);
2309 
2310     pos += size;  // consume payload
2311   }
2312 
2313   if ((m_pos < 0) || (m_track <= 0)) {
2314     return false;
2315   }
2316 
2317   return true;
2318 }
2319 
Find(const Track * pTrack) const2320 const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
2321   assert(pTrack);
2322 
2323   const long long n = pTrack->GetNumber();
2324 
2325   const TrackPosition* i = m_track_positions;
2326   const TrackPosition* const j = i + m_track_positions_count;
2327 
2328   while (i != j) {
2329     const TrackPosition& p = *i++;
2330 
2331     if (p.m_track == n)
2332       return &p;
2333   }
2334 
2335   return NULL;  // no matching track number found
2336 }
2337 
GetTimeCode() const2338 long long CuePoint::GetTimeCode() const { return m_timecode; }
2339 
GetTime(const Segment * pSegment) const2340 long long CuePoint::GetTime(const Segment* pSegment) const {
2341   assert(pSegment);
2342   assert(m_timecode >= 0);
2343 
2344   const SegmentInfo* const pInfo = pSegment->GetInfo();
2345   assert(pInfo);
2346 
2347   const long long scale = pInfo->GetTimeCodeScale();
2348   assert(scale >= 1);
2349 
2350   const long long time = scale * m_timecode;
2351 
2352   return time;
2353 }
2354 
DoneParsing() const2355 bool Segment::DoneParsing() const {
2356   if (m_size < 0) {
2357     long long total, avail;
2358 
2359     const int status = m_pReader->Length(&total, &avail);
2360 
2361     if (status < 0)  // error
2362       return true;  // must assume done
2363 
2364     if (total < 0)
2365       return false;  // assume live stream
2366 
2367     return (m_pos >= total);
2368   }
2369 
2370   const long long stop = m_start + m_size;
2371 
2372   return (m_pos >= stop);
2373 }
2374 
GetFirst() const2375 const Cluster* Segment::GetFirst() const {
2376   if ((m_clusters == NULL) || (m_clusterCount <= 0))
2377     return &m_eos;
2378 
2379   Cluster* const pCluster = m_clusters[0];
2380   assert(pCluster);
2381 
2382   return pCluster;
2383 }
2384 
GetLast() const2385 const Cluster* Segment::GetLast() const {
2386   if ((m_clusters == NULL) || (m_clusterCount <= 0))
2387     return &m_eos;
2388 
2389   const long idx = m_clusterCount - 1;
2390 
2391   Cluster* const pCluster = m_clusters[idx];
2392   assert(pCluster);
2393 
2394   return pCluster;
2395 }
2396 
GetCount() const2397 unsigned long Segment::GetCount() const { return m_clusterCount; }
2398 
GetNext(const Cluster * pCurr)2399 const Cluster* Segment::GetNext(const Cluster* pCurr) {
2400   assert(pCurr);
2401   assert(pCurr != &m_eos);
2402   assert(m_clusters);
2403 
2404   long idx = pCurr->m_index;
2405 
2406   if (idx >= 0) {
2407     assert(m_clusterCount > 0);
2408     assert(idx < m_clusterCount);
2409     assert(pCurr == m_clusters[idx]);
2410 
2411     ++idx;
2412 
2413     if (idx >= m_clusterCount)
2414       return &m_eos;  // caller will LoadCluster as desired
2415 
2416     Cluster* const pNext = m_clusters[idx];
2417     assert(pNext);
2418     assert(pNext->m_index >= 0);
2419     assert(pNext->m_index == idx);
2420 
2421     return pNext;
2422   }
2423 
2424   assert(m_clusterPreloadCount > 0);
2425 
2426   long long pos = pCurr->m_element_start;
2427 
2428   assert(m_size >= 0);  // TODO
2429   const long long stop = m_start + m_size;  // end of segment
2430 
2431   {
2432     long len;
2433 
2434     long long result = GetUIntLength(m_pReader, pos, len);
2435     assert(result == 0);
2436     assert((pos + len) <= stop);  // TODO
2437     if (result != 0)
2438       return NULL;
2439 
2440     const long long id = ReadUInt(m_pReader, pos, len);
2441     assert(id == 0x0F43B675);  // Cluster ID
2442     if (id != 0x0F43B675)
2443       return NULL;
2444 
2445     pos += len;  // consume ID
2446 
2447     // Read Size
2448     result = GetUIntLength(m_pReader, pos, len);
2449     assert(result == 0);  // TODO
2450     assert((pos + len) <= stop);  // TODO
2451 
2452     const long long size = ReadUInt(m_pReader, pos, len);
2453     assert(size > 0);  // TODO
2454     // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
2455 
2456     pos += len;  // consume length of size of element
2457     assert((pos + size) <= stop);  // TODO
2458 
2459     // Pos now points to start of payload
2460 
2461     pos += size;  // consume payload
2462   }
2463 
2464   long long off_next = 0;
2465 
2466   while (pos < stop) {
2467     long len;
2468 
2469     long long result = GetUIntLength(m_pReader, pos, len);
2470     assert(result == 0);
2471     assert((pos + len) <= stop);  // TODO
2472     if (result != 0)
2473       return NULL;
2474 
2475     const long long idpos = pos;  // pos of next (potential) cluster
2476 
2477     const long long id = ReadUInt(m_pReader, idpos, len);
2478     assert(id > 0);  // TODO
2479 
2480     pos += len;  // consume ID
2481 
2482     // Read Size
2483     result = GetUIntLength(m_pReader, pos, len);
2484     assert(result == 0);  // TODO
2485     assert((pos + len) <= stop);  // TODO
2486 
2487     const long long size = ReadUInt(m_pReader, pos, len);
2488     assert(size >= 0);  // TODO
2489 
2490     pos += len;  // consume length of size of element
2491     assert((pos + size) <= stop);  // TODO
2492 
2493     // Pos now points to start of payload
2494 
2495     if (size == 0)  // weird
2496       continue;
2497 
2498     if (id == 0x0F43B675) {  // Cluster ID
2499       const long long off_next_ = idpos - m_start;
2500 
2501       long long pos_;
2502       long len_;
2503 
2504       const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);
2505 
2506       assert(status >= 0);
2507 
2508       if (status > 0) {
2509         off_next = off_next_;
2510         break;
2511       }
2512     }
2513 
2514     pos += size;  // consume payload
2515   }
2516 
2517   if (off_next <= 0)
2518     return 0;
2519 
2520   Cluster** const ii = m_clusters + m_clusterCount;
2521   Cluster** i = ii;
2522 
2523   Cluster** const jj = ii + m_clusterPreloadCount;
2524   Cluster** j = jj;
2525 
2526   while (i < j) {
2527     // INVARIANT:
2528     //[0, i) < pos_next
2529     //[i, j) ?
2530     //[j, jj)  > pos_next
2531 
2532     Cluster** const k = i + (j - i) / 2;
2533     assert(k < jj);
2534 
2535     Cluster* const pNext = *k;
2536     assert(pNext);
2537     assert(pNext->m_index < 0);
2538 
2539     // const long long pos_ = pNext->m_pos;
2540     // assert(pos_);
2541     // pos = pos_ * ((pos_ < 0) ? -1 : 1);
2542 
2543     pos = pNext->GetPosition();
2544 
2545     if (pos < off_next)
2546       i = k + 1;
2547     else if (pos > off_next)
2548       j = k;
2549     else
2550       return pNext;
2551   }
2552 
2553   assert(i == j);
2554 
2555   Cluster* const pNext = Cluster::Create(this, -1, off_next);
2556   assert(pNext);
2557 
2558   const ptrdiff_t idx_next = i - m_clusters;  // insertion position
2559 
2560   PreloadCluster(pNext, idx_next);
2561   assert(m_clusters);
2562   assert(idx_next < m_clusterSize);
2563   assert(m_clusters[idx_next] == pNext);
2564 
2565   return pNext;
2566 }
2567 
ParseNext(const Cluster * pCurr,const Cluster * & pResult,long long & pos,long & len)2568 long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
2569                         long long& pos, long& len) {
2570   assert(pCurr);
2571   assert(!pCurr->EOS());
2572   assert(m_clusters);
2573 
2574   pResult = 0;
2575 
2576   if (pCurr->m_index >= 0) {  // loaded (not merely preloaded)
2577     assert(m_clusters[pCurr->m_index] == pCurr);
2578 
2579     const long next_idx = pCurr->m_index + 1;
2580 
2581     if (next_idx < m_clusterCount) {
2582       pResult = m_clusters[next_idx];
2583       return 0;  // success
2584     }
2585 
2586     // curr cluster is last among loaded
2587 
2588     const long result = LoadCluster(pos, len);
2589 
2590     if (result < 0)  // error or underflow
2591       return result;
2592 
2593     if (result > 0)  // no more clusters
2594     {
2595       // pResult = &m_eos;
2596       return 1;
2597     }
2598 
2599     pResult = GetLast();
2600     return 0;  // success
2601   }
2602 
2603   assert(m_pos > 0);
2604 
2605   long long total, avail;
2606 
2607   long status = m_pReader->Length(&total, &avail);
2608 
2609   if (status < 0)  // error
2610     return status;
2611 
2612   assert((total < 0) || (avail <= total));
2613 
2614   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
2615 
2616   // interrogate curr cluster
2617 
2618   pos = pCurr->m_element_start;
2619 
2620   if (pCurr->m_element_size >= 0)
2621     pos += pCurr->m_element_size;
2622   else {
2623     if ((pos + 1) > avail) {
2624       len = 1;
2625       return E_BUFFER_NOT_FULL;
2626     }
2627 
2628     long long result = GetUIntLength(m_pReader, pos, len);
2629 
2630     if (result < 0)  // error
2631       return static_cast<long>(result);
2632 
2633     if (result > 0)  // weird
2634       return E_BUFFER_NOT_FULL;
2635 
2636     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2637       return E_FILE_FORMAT_INVALID;
2638 
2639     if ((pos + len) > avail)
2640       return E_BUFFER_NOT_FULL;
2641 
2642     const long long id = ReadUInt(m_pReader, pos, len);
2643 
2644     if (id != 0x0F43B675)  // weird: not Cluster ID
2645       return -1;
2646 
2647     pos += len;  // consume ID
2648 
2649     // Read Size
2650 
2651     if ((pos + 1) > avail) {
2652       len = 1;
2653       return E_BUFFER_NOT_FULL;
2654     }
2655 
2656     result = GetUIntLength(m_pReader, pos, len);
2657 
2658     if (result < 0)  // error
2659       return static_cast<long>(result);
2660 
2661     if (result > 0)  // weird
2662       return E_BUFFER_NOT_FULL;
2663 
2664     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2665       return E_FILE_FORMAT_INVALID;
2666 
2667     if ((pos + len) > avail)
2668       return E_BUFFER_NOT_FULL;
2669 
2670     const long long size = ReadUInt(m_pReader, pos, len);
2671 
2672     if (size < 0)  // error
2673       return static_cast<long>(size);
2674 
2675     pos += len;  // consume size field
2676 
2677     const long long unknown_size = (1LL << (7 * len)) - 1;
2678 
2679     if (size == unknown_size)  // TODO: should never happen
2680       return E_FILE_FORMAT_INVALID;  // TODO: resolve this
2681 
2682     // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
2683 
2684     if ((segment_stop >= 0) && ((pos + size) > segment_stop))
2685       return E_FILE_FORMAT_INVALID;
2686 
2687     // Pos now points to start of payload
2688 
2689     pos += size;  // consume payload (that is, the current cluster)
2690     assert((segment_stop < 0) || (pos <= segment_stop));
2691 
2692     // By consuming the payload, we are assuming that the curr
2693     // cluster isn't interesting.  That is, we don't bother checking
2694     // whether the payload of the curr cluster is less than what
2695     // happens to be available (obtained via IMkvReader::Length).
2696     // Presumably the caller has already dispensed with the current
2697     // cluster, and really does want the next cluster.
2698   }
2699 
2700   // pos now points to just beyond the last fully-loaded cluster
2701 
2702   for (;;) {
2703     const long status = DoParseNext(pResult, pos, len);
2704 
2705     if (status <= 1)
2706       return status;
2707   }
2708 }
2709 
DoParseNext(const Cluster * & pResult,long long & pos,long & len)2710 long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
2711   long long total, avail;
2712 
2713   long status = m_pReader->Length(&total, &avail);
2714 
2715   if (status < 0)  // error
2716     return status;
2717 
2718   assert((total < 0) || (avail <= total));
2719 
2720   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
2721 
2722   // Parse next cluster.  This is strictly a parsing activity.
2723   // Creation of a new cluster object happens later, after the
2724   // parsing is done.
2725 
2726   long long off_next = 0;
2727   long long cluster_size = -1;
2728 
2729   for (;;) {
2730     if ((total >= 0) && (pos >= total))
2731       return 1;  // EOF
2732 
2733     if ((segment_stop >= 0) && (pos >= segment_stop))
2734       return 1;  // EOF
2735 
2736     if ((pos + 1) > avail) {
2737       len = 1;
2738       return E_BUFFER_NOT_FULL;
2739     }
2740 
2741     long long result = GetUIntLength(m_pReader, pos, len);
2742 
2743     if (result < 0)  // error
2744       return static_cast<long>(result);
2745 
2746     if (result > 0)  // weird
2747       return E_BUFFER_NOT_FULL;
2748 
2749     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2750       return E_FILE_FORMAT_INVALID;
2751 
2752     if ((pos + len) > avail)
2753       return E_BUFFER_NOT_FULL;
2754 
2755     const long long idpos = pos;  // absolute
2756     const long long idoff = pos - m_start;  // relative
2757 
2758     const long long id = ReadUInt(m_pReader, idpos, len);  // absolute
2759 
2760     if (id < 0)  // error
2761       return static_cast<long>(id);
2762 
2763     if (id == 0)  // weird
2764       return -1;  // generic error
2765 
2766     pos += len;  // consume ID
2767 
2768     // Read Size
2769 
2770     if ((pos + 1) > avail) {
2771       len = 1;
2772       return E_BUFFER_NOT_FULL;
2773     }
2774 
2775     result = GetUIntLength(m_pReader, pos, len);
2776 
2777     if (result < 0)  // error
2778       return static_cast<long>(result);
2779 
2780     if (result > 0)  // weird
2781       return E_BUFFER_NOT_FULL;
2782 
2783     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2784       return E_FILE_FORMAT_INVALID;
2785 
2786     if ((pos + len) > avail)
2787       return E_BUFFER_NOT_FULL;
2788 
2789     const long long size = ReadUInt(m_pReader, pos, len);
2790 
2791     if (size < 0)  // error
2792       return static_cast<long>(size);
2793 
2794     pos += len;  // consume length of size of element
2795 
2796     // Pos now points to start of payload
2797 
2798     if (size == 0)  // weird
2799       continue;
2800 
2801     const long long unknown_size = (1LL << (7 * len)) - 1;
2802 
2803     if ((segment_stop >= 0) && (size != unknown_size) &&
2804         ((pos + size) > segment_stop)) {
2805       return E_FILE_FORMAT_INVALID;
2806     }
2807 
2808     if (id == 0x0C53BB6B) {  // Cues ID
2809       if (size == unknown_size)
2810         return E_FILE_FORMAT_INVALID;
2811 
2812       const long long element_stop = pos + size;
2813 
2814       if ((segment_stop >= 0) && (element_stop > segment_stop))
2815         return E_FILE_FORMAT_INVALID;
2816 
2817       const long long element_start = idpos;
2818       const long long element_size = element_stop - element_start;
2819 
2820       if (m_pCues == NULL) {
2821         m_pCues = new Cues(this, pos, size, element_start, element_size);
2822         assert(m_pCues);  // TODO
2823       }
2824 
2825       pos += size;  // consume payload
2826       assert((segment_stop < 0) || (pos <= segment_stop));
2827 
2828       continue;
2829     }
2830 
2831     if (id != 0x0F43B675) {  // not a Cluster ID
2832       if (size == unknown_size)
2833         return E_FILE_FORMAT_INVALID;
2834 
2835       pos += size;  // consume payload
2836       assert((segment_stop < 0) || (pos <= segment_stop));
2837 
2838       continue;
2839     }
2840 
2841     // We have a cluster.
2842     off_next = idoff;
2843 
2844     if (size != unknown_size)
2845       cluster_size = size;
2846 
2847     break;
2848   }
2849 
2850   assert(off_next > 0);  // have cluster
2851 
2852   // We have parsed the next cluster.
2853   // We have not created a cluster object yet.  What we need
2854   // to do now is determine whether it has already be preloaded
2855   //(in which case, an object for this cluster has already been
2856   // created), and if not, create a new cluster object.
2857 
2858   Cluster** const ii = m_clusters + m_clusterCount;
2859   Cluster** i = ii;
2860 
2861   Cluster** const jj = ii + m_clusterPreloadCount;
2862   Cluster** j = jj;
2863 
2864   while (i < j) {
2865     // INVARIANT:
2866     //[0, i) < pos_next
2867     //[i, j) ?
2868     //[j, jj)  > pos_next
2869 
2870     Cluster** const k = i + (j - i) / 2;
2871     assert(k < jj);
2872 
2873     const Cluster* const pNext = *k;
2874     assert(pNext);
2875     assert(pNext->m_index < 0);
2876 
2877     pos = pNext->GetPosition();
2878     assert(pos >= 0);
2879 
2880     if (pos < off_next)
2881       i = k + 1;
2882     else if (pos > off_next)
2883       j = k;
2884     else {
2885       pResult = pNext;
2886       return 0;  // success
2887     }
2888   }
2889 
2890   assert(i == j);
2891 
2892   long long pos_;
2893   long len_;
2894 
2895   status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
2896 
2897   if (status < 0) {  // error or underflow
2898     pos = pos_;
2899     len = len_;
2900 
2901     return status;
2902   }
2903 
2904   if (status > 0) {  // means "found at least one block entry"
2905     Cluster* const pNext = Cluster::Create(this,
2906                                            -1,  // preloaded
2907                                            off_next);
2908     // element_size);
2909     assert(pNext);
2910 
2911     const ptrdiff_t idx_next = i - m_clusters;  // insertion position
2912 
2913     PreloadCluster(pNext, idx_next);
2914     assert(m_clusters);
2915     assert(idx_next < m_clusterSize);
2916     assert(m_clusters[idx_next] == pNext);
2917 
2918     pResult = pNext;
2919     return 0;  // success
2920   }
2921 
2922   // status == 0 means "no block entries found"
2923 
2924   if (cluster_size < 0) {  // unknown size
2925     const long long payload_pos = pos;  // absolute pos of cluster payload
2926 
2927     for (;;) {  // determine cluster size
2928       if ((total >= 0) && (pos >= total))
2929         break;
2930 
2931       if ((segment_stop >= 0) && (pos >= segment_stop))
2932         break;  // no more clusters
2933 
2934       // Read ID
2935 
2936       if ((pos + 1) > avail) {
2937         len = 1;
2938         return E_BUFFER_NOT_FULL;
2939       }
2940 
2941       long long result = GetUIntLength(m_pReader, pos, len);
2942 
2943       if (result < 0)  // error
2944         return static_cast<long>(result);
2945 
2946       if (result > 0)  // weird
2947         return E_BUFFER_NOT_FULL;
2948 
2949       if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2950         return E_FILE_FORMAT_INVALID;
2951 
2952       if ((pos + len) > avail)
2953         return E_BUFFER_NOT_FULL;
2954 
2955       const long long idpos = pos;
2956       const long long id = ReadUInt(m_pReader, idpos, len);
2957 
2958       if (id < 0)  // error (or underflow)
2959         return static_cast<long>(id);
2960 
2961       // This is the distinguished set of ID's we use to determine
2962       // that we have exhausted the sub-element's inside the cluster
2963       // whose ID we parsed earlier.
2964 
2965       if (id == 0x0F43B675)  // Cluster ID
2966         break;
2967 
2968       if (id == 0x0C53BB6B)  // Cues ID
2969         break;
2970 
2971       pos += len;  // consume ID (of sub-element)
2972 
2973       // Read Size
2974 
2975       if ((pos + 1) > avail) {
2976         len = 1;
2977         return E_BUFFER_NOT_FULL;
2978       }
2979 
2980       result = GetUIntLength(m_pReader, pos, len);
2981 
2982       if (result < 0)  // error
2983         return static_cast<long>(result);
2984 
2985       if (result > 0)  // weird
2986         return E_BUFFER_NOT_FULL;
2987 
2988       if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2989         return E_FILE_FORMAT_INVALID;
2990 
2991       if ((pos + len) > avail)
2992         return E_BUFFER_NOT_FULL;
2993 
2994       const long long size = ReadUInt(m_pReader, pos, len);
2995 
2996       if (size < 0)  // error
2997         return static_cast<long>(size);
2998 
2999       pos += len;  // consume size field of element
3000 
3001       // pos now points to start of sub-element's payload
3002 
3003       if (size == 0)  // weird
3004         continue;
3005 
3006       const long long unknown_size = (1LL << (7 * len)) - 1;
3007 
3008       if (size == unknown_size)
3009         return E_FILE_FORMAT_INVALID;  // not allowed for sub-elements
3010 
3011       if ((segment_stop >= 0) && ((pos + size) > segment_stop))  // weird
3012         return E_FILE_FORMAT_INVALID;
3013 
3014       pos += size;  // consume payload of sub-element
3015       assert((segment_stop < 0) || (pos <= segment_stop));
3016     }  // determine cluster size
3017 
3018     cluster_size = pos - payload_pos;
3019     assert(cluster_size >= 0);  // TODO: handle cluster_size = 0
3020 
3021     pos = payload_pos;  // reset and re-parse original cluster
3022   }
3023 
3024   pos += cluster_size;  // consume payload
3025   assert((segment_stop < 0) || (pos <= segment_stop));
3026 
3027   return 2;  // try to find a cluster that follows next
3028 }
3029 
FindCluster(long long time_ns) const3030 const Cluster* Segment::FindCluster(long long time_ns) const {
3031   if ((m_clusters == NULL) || (m_clusterCount <= 0))
3032     return &m_eos;
3033 
3034   {
3035     Cluster* const pCluster = m_clusters[0];
3036     assert(pCluster);
3037     assert(pCluster->m_index == 0);
3038 
3039     if (time_ns <= pCluster->GetTime())
3040       return pCluster;
3041   }
3042 
3043   // Binary search of cluster array
3044 
3045   long i = 0;
3046   long j = m_clusterCount;
3047 
3048   while (i < j) {
3049     // INVARIANT:
3050     //[0, i) <= time_ns
3051     //[i, j) ?
3052     //[j, m_clusterCount)  > time_ns
3053 
3054     const long k = i + (j - i) / 2;
3055     assert(k < m_clusterCount);
3056 
3057     Cluster* const pCluster = m_clusters[k];
3058     assert(pCluster);
3059     assert(pCluster->m_index == k);
3060 
3061     const long long t = pCluster->GetTime();
3062 
3063     if (t <= time_ns)
3064       i = k + 1;
3065     else
3066       j = k;
3067 
3068     assert(i <= j);
3069   }
3070 
3071   assert(i == j);
3072   assert(i > 0);
3073   assert(i <= m_clusterCount);
3074 
3075   const long k = i - 1;
3076 
3077   Cluster* const pCluster = m_clusters[k];
3078   assert(pCluster);
3079   assert(pCluster->m_index == k);
3080   assert(pCluster->GetTime() <= time_ns);
3081 
3082   return pCluster;
3083 }
3084 
GetTracks() const3085 const Tracks* Segment::GetTracks() const { return m_pTracks; }
GetInfo() const3086 const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
GetCues() const3087 const Cues* Segment::GetCues() const { return m_pCues; }
GetChapters() const3088 const Chapters* Segment::GetChapters() const { return m_pChapters; }
GetTags() const3089 const Tags* Segment::GetTags() const { return m_pTags; }
GetSeekHead() const3090 const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
3091 
GetDuration() const3092 long long Segment::GetDuration() const {
3093   assert(m_pInfo);
3094   return m_pInfo->GetDuration();
3095 }
3096 
Chapters(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)3097 Chapters::Chapters(Segment* pSegment, long long payload_start,
3098                    long long payload_size, long long element_start,
3099                    long long element_size)
3100     : m_pSegment(pSegment),
3101       m_start(payload_start),
3102       m_size(payload_size),
3103       m_element_start(element_start),
3104       m_element_size(element_size),
3105       m_editions(NULL),
3106       m_editions_size(0),
3107       m_editions_count(0) {}
3108 
~Chapters()3109 Chapters::~Chapters() {
3110   while (m_editions_count > 0) {
3111     Edition& e = m_editions[--m_editions_count];
3112     e.Clear();
3113   }
3114   delete[] m_editions;
3115 }
3116 
Parse()3117 long Chapters::Parse() {
3118   IMkvReader* const pReader = m_pSegment->m_pReader;
3119 
3120   long long pos = m_start;  // payload start
3121   const long long stop = pos + m_size;  // payload stop
3122 
3123   while (pos < stop) {
3124     long long id, size;
3125 
3126     long status = ParseElementHeader(pReader, pos, stop, id, size);
3127 
3128     if (status < 0)  // error
3129       return status;
3130 
3131     if (size == 0)  // weird
3132       continue;
3133 
3134     if (id == 0x05B9) {  // EditionEntry ID
3135       status = ParseEdition(pos, size);
3136 
3137       if (status < 0)  // error
3138         return status;
3139     }
3140 
3141     pos += size;
3142     assert(pos <= stop);
3143   }
3144 
3145   assert(pos == stop);
3146   return 0;
3147 }
3148 
GetEditionCount() const3149 int Chapters::GetEditionCount() const { return m_editions_count; }
3150 
GetEdition(int idx) const3151 const Chapters::Edition* Chapters::GetEdition(int idx) const {
3152   if (idx < 0)
3153     return NULL;
3154 
3155   if (idx >= m_editions_count)
3156     return NULL;
3157 
3158   return m_editions + idx;
3159 }
3160 
ExpandEditionsArray()3161 bool Chapters::ExpandEditionsArray() {
3162   if (m_editions_size > m_editions_count)
3163     return true;  // nothing else to do
3164 
3165   const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
3166 
3167   Edition* const editions = new (std::nothrow) Edition[size];
3168 
3169   if (editions == NULL)
3170     return false;
3171 
3172   for (int idx = 0; idx < m_editions_count; ++idx) {
3173     m_editions[idx].ShallowCopy(editions[idx]);
3174   }
3175 
3176   delete[] m_editions;
3177   m_editions = editions;
3178 
3179   m_editions_size = size;
3180   return true;
3181 }
3182 
ParseEdition(long long pos,long long size)3183 long Chapters::ParseEdition(long long pos, long long size) {
3184   if (!ExpandEditionsArray())
3185     return -1;
3186 
3187   Edition& e = m_editions[m_editions_count++];
3188   e.Init();
3189 
3190   return e.Parse(m_pSegment->m_pReader, pos, size);
3191 }
3192 
Edition()3193 Chapters::Edition::Edition() {}
3194 
~Edition()3195 Chapters::Edition::~Edition() {}
3196 
GetAtomCount() const3197 int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
3198 
GetAtom(int index) const3199 const Chapters::Atom* Chapters::Edition::GetAtom(int index) const {
3200   if (index < 0)
3201     return NULL;
3202 
3203   if (index >= m_atoms_count)
3204     return NULL;
3205 
3206   return m_atoms + index;
3207 }
3208 
Init()3209 void Chapters::Edition::Init() {
3210   m_atoms = NULL;
3211   m_atoms_size = 0;
3212   m_atoms_count = 0;
3213 }
3214 
ShallowCopy(Edition & rhs) const3215 void Chapters::Edition::ShallowCopy(Edition& rhs) const {
3216   rhs.m_atoms = m_atoms;
3217   rhs.m_atoms_size = m_atoms_size;
3218   rhs.m_atoms_count = m_atoms_count;
3219 }
3220 
Clear()3221 void Chapters::Edition::Clear() {
3222   while (m_atoms_count > 0) {
3223     Atom& a = m_atoms[--m_atoms_count];
3224     a.Clear();
3225   }
3226 
3227   delete[] m_atoms;
3228   m_atoms = NULL;
3229 
3230   m_atoms_size = 0;
3231 }
3232 
Parse(IMkvReader * pReader,long long pos,long long size)3233 long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
3234                               long long size) {
3235   const long long stop = pos + size;
3236 
3237   while (pos < stop) {
3238     long long id, size;
3239 
3240     long status = ParseElementHeader(pReader, pos, stop, id, size);
3241 
3242     if (status < 0)  // error
3243       return status;
3244 
3245     if (size == 0)  // weird
3246       continue;
3247 
3248     if (id == 0x36) {  // Atom ID
3249       status = ParseAtom(pReader, pos, size);
3250 
3251       if (status < 0)  // error
3252         return status;
3253     }
3254 
3255     pos += size;
3256     assert(pos <= stop);
3257   }
3258 
3259   assert(pos == stop);
3260   return 0;
3261 }
3262 
ParseAtom(IMkvReader * pReader,long long pos,long long size)3263 long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos,
3264                                   long long size) {
3265   if (!ExpandAtomsArray())
3266     return -1;
3267 
3268   Atom& a = m_atoms[m_atoms_count++];
3269   a.Init();
3270 
3271   return a.Parse(pReader, pos, size);
3272 }
3273 
ExpandAtomsArray()3274 bool Chapters::Edition::ExpandAtomsArray() {
3275   if (m_atoms_size > m_atoms_count)
3276     return true;  // nothing else to do
3277 
3278   const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
3279 
3280   Atom* const atoms = new (std::nothrow) Atom[size];
3281 
3282   if (atoms == NULL)
3283     return false;
3284 
3285   for (int idx = 0; idx < m_atoms_count; ++idx) {
3286     m_atoms[idx].ShallowCopy(atoms[idx]);
3287   }
3288 
3289   delete[] m_atoms;
3290   m_atoms = atoms;
3291 
3292   m_atoms_size = size;
3293   return true;
3294 }
3295 
Atom()3296 Chapters::Atom::Atom() {}
3297 
~Atom()3298 Chapters::Atom::~Atom() {}
3299 
GetUID() const3300 unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
3301 
GetStringUID() const3302 const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
3303 
GetStartTimecode() const3304 long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
3305 
GetStopTimecode() const3306 long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
3307 
GetStartTime(const Chapters * pChapters) const3308 long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
3309   return GetTime(pChapters, m_start_timecode);
3310 }
3311 
GetStopTime(const Chapters * pChapters) const3312 long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
3313   return GetTime(pChapters, m_stop_timecode);
3314 }
3315 
GetDisplayCount() const3316 int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
3317 
GetDisplay(int index) const3318 const Chapters::Display* Chapters::Atom::GetDisplay(int index) const {
3319   if (index < 0)
3320     return NULL;
3321 
3322   if (index >= m_displays_count)
3323     return NULL;
3324 
3325   return m_displays + index;
3326 }
3327 
Init()3328 void Chapters::Atom::Init() {
3329   m_string_uid = NULL;
3330   m_uid = 0;
3331   m_start_timecode = -1;
3332   m_stop_timecode = -1;
3333 
3334   m_displays = NULL;
3335   m_displays_size = 0;
3336   m_displays_count = 0;
3337 }
3338 
ShallowCopy(Atom & rhs) const3339 void Chapters::Atom::ShallowCopy(Atom& rhs) const {
3340   rhs.m_string_uid = m_string_uid;
3341   rhs.m_uid = m_uid;
3342   rhs.m_start_timecode = m_start_timecode;
3343   rhs.m_stop_timecode = m_stop_timecode;
3344 
3345   rhs.m_displays = m_displays;
3346   rhs.m_displays_size = m_displays_size;
3347   rhs.m_displays_count = m_displays_count;
3348 }
3349 
Clear()3350 void Chapters::Atom::Clear() {
3351   delete[] m_string_uid;
3352   m_string_uid = NULL;
3353 
3354   while (m_displays_count > 0) {
3355     Display& d = m_displays[--m_displays_count];
3356     d.Clear();
3357   }
3358 
3359   delete[] m_displays;
3360   m_displays = NULL;
3361 
3362   m_displays_size = 0;
3363 }
3364 
Parse(IMkvReader * pReader,long long pos,long long size)3365 long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
3366   const long long stop = pos + size;
3367 
3368   while (pos < stop) {
3369     long long id, size;
3370 
3371     long status = ParseElementHeader(pReader, pos, stop, id, size);
3372 
3373     if (status < 0)  // error
3374       return status;
3375 
3376     if (size == 0)  // weird
3377       continue;
3378 
3379     if (id == 0x00) {  // Display ID
3380       status = ParseDisplay(pReader, pos, size);
3381 
3382       if (status < 0)  // error
3383         return status;
3384     } else if (id == 0x1654) {  // StringUID ID
3385       status = UnserializeString(pReader, pos, size, m_string_uid);
3386 
3387       if (status < 0)  // error
3388         return status;
3389     } else if (id == 0x33C4) {  // UID ID
3390       long long val;
3391       status = UnserializeInt(pReader, pos, size, val);
3392 
3393       if (status < 0)  // error
3394         return status;
3395 
3396       m_uid = static_cast<unsigned long long>(val);
3397     } else if (id == 0x11) {  // TimeStart ID
3398       const long long val = UnserializeUInt(pReader, pos, size);
3399 
3400       if (val < 0)  // error
3401         return static_cast<long>(val);
3402 
3403       m_start_timecode = val;
3404     } else if (id == 0x12) {  // TimeEnd ID
3405       const long long val = UnserializeUInt(pReader, pos, size);
3406 
3407       if (val < 0)  // error
3408         return static_cast<long>(val);
3409 
3410       m_stop_timecode = val;
3411     }
3412 
3413     pos += size;
3414     assert(pos <= stop);
3415   }
3416 
3417   assert(pos == stop);
3418   return 0;
3419 }
3420 
GetTime(const Chapters * pChapters,long long timecode)3421 long long Chapters::Atom::GetTime(const Chapters* pChapters,
3422                                   long long timecode) {
3423   if (pChapters == NULL)
3424     return -1;
3425 
3426   Segment* const pSegment = pChapters->m_pSegment;
3427 
3428   if (pSegment == NULL)  // weird
3429     return -1;
3430 
3431   const SegmentInfo* const pInfo = pSegment->GetInfo();
3432 
3433   if (pInfo == NULL)
3434     return -1;
3435 
3436   const long long timecode_scale = pInfo->GetTimeCodeScale();
3437 
3438   if (timecode_scale < 1)  // weird
3439     return -1;
3440 
3441   if (timecode < 0)
3442     return -1;
3443 
3444   const long long result = timecode_scale * timecode;
3445 
3446   return result;
3447 }
3448 
ParseDisplay(IMkvReader * pReader,long long pos,long long size)3449 long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos,
3450                                   long long size) {
3451   if (!ExpandDisplaysArray())
3452     return -1;
3453 
3454   Display& d = m_displays[m_displays_count++];
3455   d.Init();
3456 
3457   return d.Parse(pReader, pos, size);
3458 }
3459 
ExpandDisplaysArray()3460 bool Chapters::Atom::ExpandDisplaysArray() {
3461   if (m_displays_size > m_displays_count)
3462     return true;  // nothing else to do
3463 
3464   const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
3465 
3466   Display* const displays = new (std::nothrow) Display[size];
3467 
3468   if (displays == NULL)
3469     return false;
3470 
3471   for (int idx = 0; idx < m_displays_count; ++idx) {
3472     m_displays[idx].ShallowCopy(displays[idx]);
3473   }
3474 
3475   delete[] m_displays;
3476   m_displays = displays;
3477 
3478   m_displays_size = size;
3479   return true;
3480 }
3481 
Display()3482 Chapters::Display::Display() {}
3483 
~Display()3484 Chapters::Display::~Display() {}
3485 
GetString() const3486 const char* Chapters::Display::GetString() const { return m_string; }
3487 
GetLanguage() const3488 const char* Chapters::Display::GetLanguage() const { return m_language; }
3489 
GetCountry() const3490 const char* Chapters::Display::GetCountry() const { return m_country; }
3491 
Init()3492 void Chapters::Display::Init() {
3493   m_string = NULL;
3494   m_language = NULL;
3495   m_country = NULL;
3496 }
3497 
ShallowCopy(Display & rhs) const3498 void Chapters::Display::ShallowCopy(Display& rhs) const {
3499   rhs.m_string = m_string;
3500   rhs.m_language = m_language;
3501   rhs.m_country = m_country;
3502 }
3503 
Clear()3504 void Chapters::Display::Clear() {
3505   delete[] m_string;
3506   m_string = NULL;
3507 
3508   delete[] m_language;
3509   m_language = NULL;
3510 
3511   delete[] m_country;
3512   m_country = NULL;
3513 }
3514 
Parse(IMkvReader * pReader,long long pos,long long size)3515 long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
3516                               long long size) {
3517   const long long stop = pos + size;
3518 
3519   while (pos < stop) {
3520     long long id, size;
3521 
3522     long status = ParseElementHeader(pReader, pos, stop, id, size);
3523 
3524     if (status < 0)  // error
3525       return status;
3526 
3527     if (size == 0)  // weird
3528       continue;
3529 
3530     if (id == 0x05) {  // ChapterString ID
3531       status = UnserializeString(pReader, pos, size, m_string);
3532 
3533       if (status)
3534         return status;
3535     } else if (id == 0x037C) {  // ChapterLanguage ID
3536       status = UnserializeString(pReader, pos, size, m_language);
3537 
3538       if (status)
3539         return status;
3540     } else if (id == 0x037E) {  // ChapterCountry ID
3541       status = UnserializeString(pReader, pos, size, m_country);
3542 
3543       if (status)
3544         return status;
3545     }
3546 
3547     pos += size;
3548     assert(pos <= stop);
3549   }
3550 
3551   assert(pos == stop);
3552   return 0;
3553 }
3554 
Tags(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)3555 Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size,
3556            long long element_start, long long element_size)
3557     : m_pSegment(pSegment),
3558       m_start(payload_start),
3559       m_size(payload_size),
3560       m_element_start(element_start),
3561       m_element_size(element_size),
3562       m_tags(NULL),
3563       m_tags_size(0),
3564       m_tags_count(0) {}
3565 
~Tags()3566 Tags::~Tags() {
3567   while (m_tags_count > 0) {
3568     Tag& t = m_tags[--m_tags_count];
3569     t.Clear();
3570   }
3571   delete[] m_tags;
3572 }
3573 
Parse()3574 long Tags::Parse() {
3575   IMkvReader* const pReader = m_pSegment->m_pReader;
3576 
3577   long long pos = m_start;  // payload start
3578   const long long stop = pos + m_size;  // payload stop
3579 
3580   while (pos < stop) {
3581     long long id, size;
3582 
3583     long status = ParseElementHeader(pReader, pos, stop, id, size);
3584 
3585     if (status < 0)
3586       return status;
3587 
3588     if (size == 0)  // 0 length tag, read another
3589       continue;
3590 
3591     if (id == 0x3373) {  // Tag ID
3592       status = ParseTag(pos, size);
3593 
3594       if (status < 0)
3595         return status;
3596     }
3597 
3598     pos += size;
3599     assert(pos <= stop);
3600     if (pos > stop)
3601       return -1;
3602   }
3603 
3604   assert(pos == stop);
3605   if (pos != stop)
3606     return -1;
3607 
3608   return 0;
3609 }
3610 
GetTagCount() const3611 int Tags::GetTagCount() const { return m_tags_count; }
3612 
GetTag(int idx) const3613 const Tags::Tag* Tags::GetTag(int idx) const {
3614   if (idx < 0)
3615     return NULL;
3616 
3617   if (idx >= m_tags_count)
3618     return NULL;
3619 
3620   return m_tags + idx;
3621 }
3622 
ExpandTagsArray()3623 bool Tags::ExpandTagsArray() {
3624   if (m_tags_size > m_tags_count)
3625     return true;  // nothing else to do
3626 
3627   const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
3628 
3629   Tag* const tags = new (std::nothrow) Tag[size];
3630 
3631   if (tags == NULL)
3632     return false;
3633 
3634   for (int idx = 0; idx < m_tags_count; ++idx) {
3635     m_tags[idx].ShallowCopy(tags[idx]);
3636   }
3637 
3638   delete[] m_tags;
3639   m_tags = tags;
3640 
3641   m_tags_size = size;
3642   return true;
3643 }
3644 
ParseTag(long long pos,long long size)3645 long Tags::ParseTag(long long pos, long long size) {
3646   if (!ExpandTagsArray())
3647     return -1;
3648 
3649   Tag& t = m_tags[m_tags_count++];
3650   t.Init();
3651 
3652   return t.Parse(m_pSegment->m_pReader, pos, size);
3653 }
3654 
Tag()3655 Tags::Tag::Tag() {}
3656 
~Tag()3657 Tags::Tag::~Tag() {}
3658 
GetSimpleTagCount() const3659 int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
3660 
GetSimpleTag(int index) const3661 const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const {
3662   if (index < 0)
3663     return NULL;
3664 
3665   if (index >= m_simple_tags_count)
3666     return NULL;
3667 
3668   return m_simple_tags + index;
3669 }
3670 
Init()3671 void Tags::Tag::Init() {
3672   m_simple_tags = NULL;
3673   m_simple_tags_size = 0;
3674   m_simple_tags_count = 0;
3675 }
3676 
ShallowCopy(Tag & rhs) const3677 void Tags::Tag::ShallowCopy(Tag& rhs) const {
3678   rhs.m_simple_tags = m_simple_tags;
3679   rhs.m_simple_tags_size = m_simple_tags_size;
3680   rhs.m_simple_tags_count = m_simple_tags_count;
3681 }
3682 
Clear()3683 void Tags::Tag::Clear() {
3684   while (m_simple_tags_count > 0) {
3685     SimpleTag& d = m_simple_tags[--m_simple_tags_count];
3686     d.Clear();
3687   }
3688 
3689   delete[] m_simple_tags;
3690   m_simple_tags = NULL;
3691 
3692   m_simple_tags_size = 0;
3693 }
3694 
Parse(IMkvReader * pReader,long long pos,long long size)3695 long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
3696   const long long stop = pos + size;
3697 
3698   while (pos < stop) {
3699     long long id, size;
3700 
3701     long status = ParseElementHeader(pReader, pos, stop, id, size);
3702 
3703     if (status < 0)
3704       return status;
3705 
3706     if (size == 0)  // 0 length tag, read another
3707       continue;
3708 
3709     if (id == 0x27C8) {  // SimpleTag ID
3710       status = ParseSimpleTag(pReader, pos, size);
3711 
3712       if (status < 0)
3713         return status;
3714     }
3715 
3716     pos += size;
3717     assert(pos <= stop);
3718     if (pos > stop)
3719       return -1;
3720   }
3721 
3722   assert(pos == stop);
3723   if (pos != stop)
3724     return -1;
3725   return 0;
3726 }
3727 
ParseSimpleTag(IMkvReader * pReader,long long pos,long long size)3728 long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos,
3729                                long long size) {
3730   if (!ExpandSimpleTagsArray())
3731     return -1;
3732 
3733   SimpleTag& st = m_simple_tags[m_simple_tags_count++];
3734   st.Init();
3735 
3736   return st.Parse(pReader, pos, size);
3737 }
3738 
ExpandSimpleTagsArray()3739 bool Tags::Tag::ExpandSimpleTagsArray() {
3740   if (m_simple_tags_size > m_simple_tags_count)
3741     return true;  // nothing else to do
3742 
3743   const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
3744 
3745   SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
3746 
3747   if (displays == NULL)
3748     return false;
3749 
3750   for (int idx = 0; idx < m_simple_tags_count; ++idx) {
3751     m_simple_tags[idx].ShallowCopy(displays[idx]);
3752   }
3753 
3754   delete[] m_simple_tags;
3755   m_simple_tags = displays;
3756 
3757   m_simple_tags_size = size;
3758   return true;
3759 }
3760 
SimpleTag()3761 Tags::SimpleTag::SimpleTag() {}
3762 
~SimpleTag()3763 Tags::SimpleTag::~SimpleTag() {}
3764 
GetTagName() const3765 const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
3766 
GetTagString() const3767 const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
3768 
Init()3769 void Tags::SimpleTag::Init() {
3770   m_tag_name = NULL;
3771   m_tag_string = NULL;
3772 }
3773 
ShallowCopy(SimpleTag & rhs) const3774 void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
3775   rhs.m_tag_name = m_tag_name;
3776   rhs.m_tag_string = m_tag_string;
3777 }
3778 
Clear()3779 void Tags::SimpleTag::Clear() {
3780   delete[] m_tag_name;
3781   m_tag_name = NULL;
3782 
3783   delete[] m_tag_string;
3784   m_tag_string = NULL;
3785 }
3786 
Parse(IMkvReader * pReader,long long pos,long long size)3787 long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
3788                             long long size) {
3789   const long long stop = pos + size;
3790 
3791   while (pos < stop) {
3792     long long id, size;
3793 
3794     long status = ParseElementHeader(pReader, pos, stop, id, size);
3795 
3796     if (status < 0)  // error
3797       return status;
3798 
3799     if (size == 0)  // weird
3800       continue;
3801 
3802     if (id == 0x5A3) {  // TagName ID
3803       status = UnserializeString(pReader, pos, size, m_tag_name);
3804 
3805       if (status)
3806         return status;
3807     } else if (id == 0x487) {  // TagString ID
3808       status = UnserializeString(pReader, pos, size, m_tag_string);
3809 
3810       if (status)
3811         return status;
3812     }
3813 
3814     pos += size;
3815     assert(pos <= stop);
3816     if (pos > stop)
3817       return -1;
3818   }
3819 
3820   assert(pos == stop);
3821   if (pos != stop)
3822     return -1;
3823   return 0;
3824 }
3825 
SegmentInfo(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)3826 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
3827                          long long element_start, long long element_size)
3828     : m_pSegment(pSegment),
3829       m_start(start),
3830       m_size(size_),
3831       m_element_start(element_start),
3832       m_element_size(element_size),
3833       m_pMuxingAppAsUTF8(NULL),
3834       m_pWritingAppAsUTF8(NULL),
3835       m_pTitleAsUTF8(NULL) {}
3836 
~SegmentInfo()3837 SegmentInfo::~SegmentInfo() {
3838   delete[] m_pMuxingAppAsUTF8;
3839   m_pMuxingAppAsUTF8 = NULL;
3840 
3841   delete[] m_pWritingAppAsUTF8;
3842   m_pWritingAppAsUTF8 = NULL;
3843 
3844   delete[] m_pTitleAsUTF8;
3845   m_pTitleAsUTF8 = NULL;
3846 }
3847 
Parse()3848 long SegmentInfo::Parse() {
3849   assert(m_pMuxingAppAsUTF8 == NULL);
3850   assert(m_pWritingAppAsUTF8 == NULL);
3851   assert(m_pTitleAsUTF8 == NULL);
3852 
3853   IMkvReader* const pReader = m_pSegment->m_pReader;
3854 
3855   long long pos = m_start;
3856   const long long stop = m_start + m_size;
3857 
3858   m_timecodeScale = 1000000;
3859   m_duration = -1;
3860 
3861   while (pos < stop) {
3862     long long id, size;
3863 
3864     const long status = ParseElementHeader(pReader, pos, stop, id, size);
3865 
3866     if (status < 0)  // error
3867       return status;
3868 
3869     if (id == 0x0AD7B1) {  // Timecode Scale
3870       m_timecodeScale = UnserializeUInt(pReader, pos, size);
3871 
3872       if (m_timecodeScale <= 0)
3873         return E_FILE_FORMAT_INVALID;
3874     } else if (id == 0x0489) {  // Segment duration
3875       const long status = UnserializeFloat(pReader, pos, size, m_duration);
3876 
3877       if (status < 0)
3878         return status;
3879 
3880       if (m_duration < 0)
3881         return E_FILE_FORMAT_INVALID;
3882     } else if (id == 0x0D80) {  // MuxingApp
3883       const long status =
3884           UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
3885 
3886       if (status)
3887         return status;
3888     } else if (id == 0x1741) {  // WritingApp
3889       const long status =
3890           UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
3891 
3892       if (status)
3893         return status;
3894     } else if (id == 0x3BA9) {  // Title
3895       const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
3896 
3897       if (status)
3898         return status;
3899     }
3900 
3901     pos += size;
3902     assert(pos <= stop);
3903   }
3904 
3905   assert(pos == stop);
3906 
3907   return 0;
3908 }
3909 
GetTimeCodeScale() const3910 long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
3911 
GetDuration() const3912 long long SegmentInfo::GetDuration() const {
3913   if (m_duration < 0)
3914     return -1;
3915 
3916   assert(m_timecodeScale >= 1);
3917 
3918   const double dd = double(m_duration) * double(m_timecodeScale);
3919   const long long d = static_cast<long long>(dd);
3920 
3921   return d;
3922 }
3923 
GetMuxingAppAsUTF8() const3924 const char* SegmentInfo::GetMuxingAppAsUTF8() const {
3925   return m_pMuxingAppAsUTF8;
3926 }
3927 
GetWritingAppAsUTF8() const3928 const char* SegmentInfo::GetWritingAppAsUTF8() const {
3929   return m_pWritingAppAsUTF8;
3930 }
3931 
GetTitleAsUTF8() const3932 const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
3933 
3934 ///////////////////////////////////////////////////////////////
3935 // ContentEncoding element
ContentCompression()3936 ContentEncoding::ContentCompression::ContentCompression()
3937     : algo(0), settings(NULL), settings_len(0) {}
3938 
~ContentCompression()3939 ContentEncoding::ContentCompression::~ContentCompression() {
3940   delete[] settings;
3941 }
3942 
ContentEncryption()3943 ContentEncoding::ContentEncryption::ContentEncryption()
3944     : algo(0),
3945       key_id(NULL),
3946       key_id_len(0),
3947       signature(NULL),
3948       signature_len(0),
3949       sig_key_id(NULL),
3950       sig_key_id_len(0),
3951       sig_algo(0),
3952       sig_hash_algo(0) {}
3953 
~ContentEncryption()3954 ContentEncoding::ContentEncryption::~ContentEncryption() {
3955   delete[] key_id;
3956   delete[] signature;
3957   delete[] sig_key_id;
3958 }
3959 
ContentEncoding()3960 ContentEncoding::ContentEncoding()
3961     : compression_entries_(NULL),
3962       compression_entries_end_(NULL),
3963       encryption_entries_(NULL),
3964       encryption_entries_end_(NULL),
3965       encoding_order_(0),
3966       encoding_scope_(1),
3967       encoding_type_(0) {}
3968 
~ContentEncoding()3969 ContentEncoding::~ContentEncoding() {
3970   ContentCompression** comp_i = compression_entries_;
3971   ContentCompression** const comp_j = compression_entries_end_;
3972 
3973   while (comp_i != comp_j) {
3974     ContentCompression* const comp = *comp_i++;
3975     delete comp;
3976   }
3977 
3978   delete[] compression_entries_;
3979 
3980   ContentEncryption** enc_i = encryption_entries_;
3981   ContentEncryption** const enc_j = encryption_entries_end_;
3982 
3983   while (enc_i != enc_j) {
3984     ContentEncryption* const enc = *enc_i++;
3985     delete enc;
3986   }
3987 
3988   delete[] encryption_entries_;
3989 }
3990 
3991 const ContentEncoding::ContentCompression*
GetCompressionByIndex(unsigned long idx) const3992     ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
3993   const ptrdiff_t count = compression_entries_end_ - compression_entries_;
3994   assert(count >= 0);
3995 
3996   if (idx >= static_cast<unsigned long>(count))
3997     return NULL;
3998 
3999   return compression_entries_[idx];
4000 }
4001 
GetCompressionCount() const4002 unsigned long ContentEncoding::GetCompressionCount() const {
4003   const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4004   assert(count >= 0);
4005 
4006   return static_cast<unsigned long>(count);
4007 }
4008 
GetEncryptionByIndex(unsigned long idx) const4009 const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex(
4010     unsigned long idx) const {
4011   const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4012   assert(count >= 0);
4013 
4014   if (idx >= static_cast<unsigned long>(count))
4015     return NULL;
4016 
4017   return encryption_entries_[idx];
4018 }
4019 
GetEncryptionCount() const4020 unsigned long ContentEncoding::GetEncryptionCount() const {
4021   const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4022   assert(count >= 0);
4023 
4024   return static_cast<unsigned long>(count);
4025 }
4026 
ParseContentEncAESSettingsEntry(long long start,long long size,IMkvReader * pReader,ContentEncAESSettings * aes)4027 long ContentEncoding::ParseContentEncAESSettingsEntry(
4028     long long start, long long size, IMkvReader* pReader,
4029     ContentEncAESSettings* aes) {
4030   assert(pReader);
4031   assert(aes);
4032 
4033   long long pos = start;
4034   const long long stop = start + size;
4035 
4036   while (pos < stop) {
4037     long long id, size;
4038     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4039     if (status < 0)  // error
4040       return status;
4041 
4042     if (id == 0x7E8) {
4043       // AESSettingsCipherMode
4044       aes->cipher_mode = UnserializeUInt(pReader, pos, size);
4045       if (aes->cipher_mode != 1)
4046         return E_FILE_FORMAT_INVALID;
4047     }
4048 
4049     pos += size;  // consume payload
4050     assert(pos <= stop);
4051   }
4052 
4053   return 0;
4054 }
4055 
ParseContentEncodingEntry(long long start,long long size,IMkvReader * pReader)4056 long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
4057                                                 IMkvReader* pReader) {
4058   assert(pReader);
4059 
4060   long long pos = start;
4061   const long long stop = start + size;
4062 
4063   // Count ContentCompression and ContentEncryption elements.
4064   int compression_count = 0;
4065   int encryption_count = 0;
4066 
4067   while (pos < stop) {
4068     long long id, size;
4069     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4070     if (status < 0)  // error
4071       return status;
4072 
4073     if (id == 0x1034)  // ContentCompression ID
4074       ++compression_count;
4075 
4076     if (id == 0x1035)  // ContentEncryption ID
4077       ++encryption_count;
4078 
4079     pos += size;  // consume payload
4080     assert(pos <= stop);
4081   }
4082 
4083   if (compression_count <= 0 && encryption_count <= 0)
4084     return -1;
4085 
4086   if (compression_count > 0) {
4087     compression_entries_ =
4088         new (std::nothrow) ContentCompression*[compression_count];
4089     if (!compression_entries_)
4090       return -1;
4091     compression_entries_end_ = compression_entries_;
4092   }
4093 
4094   if (encryption_count > 0) {
4095     encryption_entries_ =
4096         new (std::nothrow) ContentEncryption*[encryption_count];
4097     if (!encryption_entries_) {
4098       delete[] compression_entries_;
4099       return -1;
4100     }
4101     encryption_entries_end_ = encryption_entries_;
4102   }
4103 
4104   pos = start;
4105   while (pos < stop) {
4106     long long id, size;
4107     long status = ParseElementHeader(pReader, pos, stop, id, size);
4108     if (status < 0)  // error
4109       return status;
4110 
4111     if (id == 0x1031) {
4112       // ContentEncodingOrder
4113       encoding_order_ = UnserializeUInt(pReader, pos, size);
4114     } else if (id == 0x1032) {
4115       // ContentEncodingScope
4116       encoding_scope_ = UnserializeUInt(pReader, pos, size);
4117       if (encoding_scope_ < 1)
4118         return -1;
4119     } else if (id == 0x1033) {
4120       // ContentEncodingType
4121       encoding_type_ = UnserializeUInt(pReader, pos, size);
4122     } else if (id == 0x1034) {
4123       // ContentCompression ID
4124       ContentCompression* const compression =
4125           new (std::nothrow) ContentCompression();
4126       if (!compression)
4127         return -1;
4128 
4129       status = ParseCompressionEntry(pos, size, pReader, compression);
4130       if (status) {
4131         delete compression;
4132         return status;
4133       }
4134       *compression_entries_end_++ = compression;
4135     } else if (id == 0x1035) {
4136       // ContentEncryption ID
4137       ContentEncryption* const encryption =
4138           new (std::nothrow) ContentEncryption();
4139       if (!encryption)
4140         return -1;
4141 
4142       status = ParseEncryptionEntry(pos, size, pReader, encryption);
4143       if (status) {
4144         delete encryption;
4145         return status;
4146       }
4147       *encryption_entries_end_++ = encryption;
4148     }
4149 
4150     pos += size;  // consume payload
4151     assert(pos <= stop);
4152   }
4153 
4154   assert(pos == stop);
4155   return 0;
4156 }
4157 
ParseCompressionEntry(long long start,long long size,IMkvReader * pReader,ContentCompression * compression)4158 long ContentEncoding::ParseCompressionEntry(long long start, long long size,
4159                                             IMkvReader* pReader,
4160                                             ContentCompression* compression) {
4161   assert(pReader);
4162   assert(compression);
4163 
4164   long long pos = start;
4165   const long long stop = start + size;
4166 
4167   bool valid = false;
4168 
4169   while (pos < stop) {
4170     long long id, size;
4171     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4172     if (status < 0)  // error
4173       return status;
4174 
4175     if (id == 0x254) {
4176       // ContentCompAlgo
4177       long long algo = UnserializeUInt(pReader, pos, size);
4178       if (algo < 0)
4179         return E_FILE_FORMAT_INVALID;
4180       compression->algo = algo;
4181       valid = true;
4182     } else if (id == 0x255) {
4183       // ContentCompSettings
4184       if (size <= 0)
4185         return E_FILE_FORMAT_INVALID;
4186 
4187       const size_t buflen = static_cast<size_t>(size);
4188       typedef unsigned char* buf_t;
4189       const buf_t buf = new (std::nothrow) unsigned char[buflen];
4190       if (buf == NULL)
4191         return -1;
4192 
4193       const int read_status =
4194           pReader->Read(pos, static_cast<long>(buflen), buf);
4195       if (read_status) {
4196         delete[] buf;
4197         return status;
4198       }
4199 
4200       compression->settings = buf;
4201       compression->settings_len = buflen;
4202     }
4203 
4204     pos += size;  // consume payload
4205     assert(pos <= stop);
4206   }
4207 
4208   // ContentCompAlgo is mandatory
4209   if (!valid)
4210     return E_FILE_FORMAT_INVALID;
4211 
4212   return 0;
4213 }
4214 
ParseEncryptionEntry(long long start,long long size,IMkvReader * pReader,ContentEncryption * encryption)4215 long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
4216                                            IMkvReader* pReader,
4217                                            ContentEncryption* encryption) {
4218   assert(pReader);
4219   assert(encryption);
4220 
4221   long long pos = start;
4222   const long long stop = start + size;
4223 
4224   while (pos < stop) {
4225     long long id, size;
4226     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4227     if (status < 0)  // error
4228       return status;
4229 
4230     if (id == 0x7E1) {
4231       // ContentEncAlgo
4232       encryption->algo = UnserializeUInt(pReader, pos, size);
4233       if (encryption->algo != 5)
4234         return E_FILE_FORMAT_INVALID;
4235     } else if (id == 0x7E2) {
4236       // ContentEncKeyID
4237       delete[] encryption->key_id;
4238       encryption->key_id = NULL;
4239       encryption->key_id_len = 0;
4240 
4241       if (size <= 0)
4242         return E_FILE_FORMAT_INVALID;
4243 
4244       const size_t buflen = static_cast<size_t>(size);
4245       typedef unsigned char* buf_t;
4246       const buf_t buf = new (std::nothrow) unsigned char[buflen];
4247       if (buf == NULL)
4248         return -1;
4249 
4250       const int read_status =
4251           pReader->Read(pos, static_cast<long>(buflen), buf);
4252       if (read_status) {
4253         delete[] buf;
4254         return status;
4255       }
4256 
4257       encryption->key_id = buf;
4258       encryption->key_id_len = buflen;
4259     } else if (id == 0x7E3) {
4260       // ContentSignature
4261       delete[] encryption->signature;
4262       encryption->signature = NULL;
4263       encryption->signature_len = 0;
4264 
4265       if (size <= 0)
4266         return E_FILE_FORMAT_INVALID;
4267 
4268       const size_t buflen = static_cast<size_t>(size);
4269       typedef unsigned char* buf_t;
4270       const buf_t buf = new (std::nothrow) unsigned char[buflen];
4271       if (buf == NULL)
4272         return -1;
4273 
4274       const int read_status =
4275           pReader->Read(pos, static_cast<long>(buflen), buf);
4276       if (read_status) {
4277         delete[] buf;
4278         return status;
4279       }
4280 
4281       encryption->signature = buf;
4282       encryption->signature_len = buflen;
4283     } else if (id == 0x7E4) {
4284       // ContentSigKeyID
4285       delete[] encryption->sig_key_id;
4286       encryption->sig_key_id = NULL;
4287       encryption->sig_key_id_len = 0;
4288 
4289       if (size <= 0)
4290         return E_FILE_FORMAT_INVALID;
4291 
4292       const size_t buflen = static_cast<size_t>(size);
4293       typedef unsigned char* buf_t;
4294       const buf_t buf = new (std::nothrow) unsigned char[buflen];
4295       if (buf == NULL)
4296         return -1;
4297 
4298       const int read_status =
4299           pReader->Read(pos, static_cast<long>(buflen), buf);
4300       if (read_status) {
4301         delete[] buf;
4302         return status;
4303       }
4304 
4305       encryption->sig_key_id = buf;
4306       encryption->sig_key_id_len = buflen;
4307     } else if (id == 0x7E5) {
4308       // ContentSigAlgo
4309       encryption->sig_algo = UnserializeUInt(pReader, pos, size);
4310     } else if (id == 0x7E6) {
4311       // ContentSigHashAlgo
4312       encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
4313     } else if (id == 0x7E7) {
4314       // ContentEncAESSettings
4315       const long status = ParseContentEncAESSettingsEntry(
4316           pos, size, pReader, &encryption->aes_settings);
4317       if (status)
4318         return status;
4319     }
4320 
4321     pos += size;  // consume payload
4322     assert(pos <= stop);
4323   }
4324 
4325   return 0;
4326 }
4327 
Track(Segment * pSegment,long long element_start,long long element_size)4328 Track::Track(Segment* pSegment, long long element_start, long long element_size)
4329     : m_pSegment(pSegment),
4330       m_element_start(element_start),
4331       m_element_size(element_size),
4332       content_encoding_entries_(NULL),
4333       content_encoding_entries_end_(NULL) {}
4334 
~Track()4335 Track::~Track() {
4336   Info& info = const_cast<Info&>(m_info);
4337   info.Clear();
4338 
4339   ContentEncoding** i = content_encoding_entries_;
4340   ContentEncoding** const j = content_encoding_entries_end_;
4341 
4342   while (i != j) {
4343     ContentEncoding* const encoding = *i++;
4344     delete encoding;
4345   }
4346 
4347   delete[] content_encoding_entries_;
4348 }
4349 
Create(Segment * pSegment,const Info & info,long long element_start,long long element_size,Track * & pResult)4350 long Track::Create(Segment* pSegment, const Info& info, long long element_start,
4351                    long long element_size, Track*& pResult) {
4352   if (pResult)
4353     return -1;
4354 
4355   Track* const pTrack =
4356       new (std::nothrow) Track(pSegment, element_start, element_size);
4357 
4358   if (pTrack == NULL)
4359     return -1;  // generic error
4360 
4361   const int status = info.Copy(pTrack->m_info);
4362 
4363   if (status) {  // error
4364     delete pTrack;
4365     return status;
4366   }
4367 
4368   pResult = pTrack;
4369   return 0;  // success
4370 }
4371 
Info()4372 Track::Info::Info()
4373     : uid(0),
4374       defaultDuration(0),
4375       codecDelay(0),
4376       seekPreRoll(0),
4377       nameAsUTF8(NULL),
4378       language(NULL),
4379       codecId(NULL),
4380       codecNameAsUTF8(NULL),
4381       codecPrivate(NULL),
4382       codecPrivateSize(0),
4383       lacing(false) {}
4384 
~Info()4385 Track::Info::~Info() { Clear(); }
4386 
Clear()4387 void Track::Info::Clear() {
4388   delete[] nameAsUTF8;
4389   nameAsUTF8 = NULL;
4390 
4391   delete[] language;
4392   language = NULL;
4393 
4394   delete[] codecId;
4395   codecId = NULL;
4396 
4397   delete[] codecPrivate;
4398   codecPrivate = NULL;
4399   codecPrivateSize = 0;
4400 
4401   delete[] codecNameAsUTF8;
4402   codecNameAsUTF8 = NULL;
4403 }
4404 
CopyStr(char * Info::* str,Info & dst_) const4405 int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
4406   if (str == static_cast<char * Info::*>(NULL))
4407     return -1;
4408 
4409   char*& dst = dst_.*str;
4410 
4411   if (dst)  // should be NULL already
4412     return -1;
4413 
4414   const char* const src = this->*str;
4415 
4416   if (src == NULL)
4417     return 0;
4418 
4419   const size_t len = strlen(src);
4420 
4421   dst = new (std::nothrow) char[len + 1];
4422 
4423   if (dst == NULL)
4424     return -1;
4425 
4426   strcpy(dst, src);
4427 
4428   return 0;
4429 }
4430 
Copy(Info & dst) const4431 int Track::Info::Copy(Info& dst) const {
4432   if (&dst == this)
4433     return 0;
4434 
4435   dst.type = type;
4436   dst.number = number;
4437   dst.defaultDuration = defaultDuration;
4438   dst.codecDelay = codecDelay;
4439   dst.seekPreRoll = seekPreRoll;
4440   dst.uid = uid;
4441   dst.lacing = lacing;
4442   dst.settings = settings;
4443 
4444   // We now copy the string member variables from src to dst.
4445   // This involves memory allocation so in principle the operation
4446   // can fail (indeed, that's why we have Info::Copy), so we must
4447   // report this to the caller.  An error return from this function
4448   // therefore implies that the copy was only partially successful.
4449 
4450   if (int status = CopyStr(&Info::nameAsUTF8, dst))
4451     return status;
4452 
4453   if (int status = CopyStr(&Info::language, dst))
4454     return status;
4455 
4456   if (int status = CopyStr(&Info::codecId, dst))
4457     return status;
4458 
4459   if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
4460     return status;
4461 
4462   if (codecPrivateSize > 0) {
4463     if (codecPrivate == NULL)
4464       return -1;
4465 
4466     if (dst.codecPrivate)
4467       return -1;
4468 
4469     if (dst.codecPrivateSize != 0)
4470       return -1;
4471 
4472     dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize];
4473 
4474     if (dst.codecPrivate == NULL)
4475       return -1;
4476 
4477     memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
4478     dst.codecPrivateSize = codecPrivateSize;
4479   }
4480 
4481   return 0;
4482 }
4483 
GetEOS() const4484 const BlockEntry* Track::GetEOS() const { return &m_eos; }
4485 
GetType() const4486 long Track::GetType() const { return m_info.type; }
4487 
GetNumber() const4488 long Track::GetNumber() const { return m_info.number; }
4489 
GetUid() const4490 unsigned long long Track::GetUid() const { return m_info.uid; }
4491 
GetNameAsUTF8() const4492 const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
4493 
GetLanguage() const4494 const char* Track::GetLanguage() const { return m_info.language; }
4495 
GetCodecNameAsUTF8() const4496 const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
4497 
GetCodecId() const4498 const char* Track::GetCodecId() const { return m_info.codecId; }
4499 
GetCodecPrivate(size_t & size) const4500 const unsigned char* Track::GetCodecPrivate(size_t& size) const {
4501   size = m_info.codecPrivateSize;
4502   return m_info.codecPrivate;
4503 }
4504 
GetLacing() const4505 bool Track::GetLacing() const { return m_info.lacing; }
4506 
GetDefaultDuration() const4507 unsigned long long Track::GetDefaultDuration() const {
4508   return m_info.defaultDuration;
4509 }
4510 
GetCodecDelay() const4511 unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
4512 
GetSeekPreRoll() const4513 unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
4514 
GetFirst(const BlockEntry * & pBlockEntry) const4515 long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
4516   const Cluster* pCluster = m_pSegment->GetFirst();
4517 
4518   for (int i = 0;;) {
4519     if (pCluster == NULL) {
4520       pBlockEntry = GetEOS();
4521       return 1;
4522     }
4523 
4524     if (pCluster->EOS()) {
4525       if (m_pSegment->DoneParsing()) {
4526         pBlockEntry = GetEOS();
4527         return 1;
4528       }
4529 
4530       pBlockEntry = 0;
4531       return E_BUFFER_NOT_FULL;
4532     }
4533 
4534     long status = pCluster->GetFirst(pBlockEntry);
4535 
4536     if (status < 0)  // error
4537       return status;
4538 
4539     if (pBlockEntry == 0) {  // empty cluster
4540       pCluster = m_pSegment->GetNext(pCluster);
4541       continue;
4542     }
4543 
4544     for (;;) {
4545       const Block* const pBlock = pBlockEntry->GetBlock();
4546       assert(pBlock);
4547 
4548       const long long tn = pBlock->GetTrackNumber();
4549 
4550       if ((tn == m_info.number) && VetEntry(pBlockEntry))
4551         return 0;
4552 
4553       const BlockEntry* pNextEntry;
4554 
4555       status = pCluster->GetNext(pBlockEntry, pNextEntry);
4556 
4557       if (status < 0)  // error
4558         return status;
4559 
4560       if (pNextEntry == 0)
4561         break;
4562 
4563       pBlockEntry = pNextEntry;
4564     }
4565 
4566     ++i;
4567 
4568     if (i >= 100)
4569       break;
4570 
4571     pCluster = m_pSegment->GetNext(pCluster);
4572   }
4573 
4574   // NOTE: if we get here, it means that we didn't find a block with
4575   // a matching track number.  We interpret that as an error (which
4576   // might be too conservative).
4577 
4578   pBlockEntry = GetEOS();  // so we can return a non-NULL value
4579   return 1;
4580 }
4581 
GetNext(const BlockEntry * pCurrEntry,const BlockEntry * & pNextEntry) const4582 long Track::GetNext(const BlockEntry* pCurrEntry,
4583                     const BlockEntry*& pNextEntry) const {
4584   assert(pCurrEntry);
4585   assert(!pCurrEntry->EOS());  //?
4586 
4587   const Block* const pCurrBlock = pCurrEntry->GetBlock();
4588   assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
4589   if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
4590     return -1;
4591 
4592   const Cluster* pCluster = pCurrEntry->GetCluster();
4593   assert(pCluster);
4594   assert(!pCluster->EOS());
4595 
4596   long status = pCluster->GetNext(pCurrEntry, pNextEntry);
4597 
4598   if (status < 0)  // error
4599     return status;
4600 
4601   for (int i = 0;;) {
4602     while (pNextEntry) {
4603       const Block* const pNextBlock = pNextEntry->GetBlock();
4604       assert(pNextBlock);
4605 
4606       if (pNextBlock->GetTrackNumber() == m_info.number)
4607         return 0;
4608 
4609       pCurrEntry = pNextEntry;
4610 
4611       status = pCluster->GetNext(pCurrEntry, pNextEntry);
4612 
4613       if (status < 0)  // error
4614         return status;
4615     }
4616 
4617     pCluster = m_pSegment->GetNext(pCluster);
4618 
4619     if (pCluster == NULL) {
4620       pNextEntry = GetEOS();
4621       return 1;
4622     }
4623 
4624     if (pCluster->EOS()) {
4625       if (m_pSegment->DoneParsing()) {
4626         pNextEntry = GetEOS();
4627         return 1;
4628       }
4629 
4630       // TODO: there is a potential O(n^2) problem here: we tell the
4631       // caller to (pre)load another cluster, which he does, but then he
4632       // calls GetNext again, which repeats the same search.  This is
4633       // a pathological case, since the only way it can happen is if
4634       // there exists a long sequence of clusters none of which contain a
4635       // block from this track.  One way around this problem is for the
4636       // caller to be smarter when he loads another cluster: don't call
4637       // us back until you have a cluster that contains a block from this
4638       // track. (Of course, that's not cheap either, since our caller
4639       // would have to scan the each cluster as it's loaded, so that
4640       // would just push back the problem.)
4641 
4642       pNextEntry = NULL;
4643       return E_BUFFER_NOT_FULL;
4644     }
4645 
4646     status = pCluster->GetFirst(pNextEntry);
4647 
4648     if (status < 0)  // error
4649       return status;
4650 
4651     if (pNextEntry == NULL)  // empty cluster
4652       continue;
4653 
4654     ++i;
4655 
4656     if (i >= 100)
4657       break;
4658   }
4659 
4660   // NOTE: if we get here, it means that we didn't find a block with
4661   // a matching track number after lots of searching, so we give
4662   // up trying.
4663 
4664   pNextEntry = GetEOS();  // so we can return a non-NULL value
4665   return 1;
4666 }
4667 
VetEntry(const BlockEntry * pBlockEntry) const4668 bool Track::VetEntry(const BlockEntry* pBlockEntry) const {
4669   assert(pBlockEntry);
4670   const Block* const pBlock = pBlockEntry->GetBlock();
4671   assert(pBlock);
4672   assert(pBlock->GetTrackNumber() == m_info.number);
4673   if (!pBlock || pBlock->GetTrackNumber() != m_info.number)
4674     return false;
4675 
4676   // This function is used during a seek to determine whether the
4677   // frame is a valid seek target.  This default function simply
4678   // returns true, which means all frames are valid seek targets.
4679   // It gets overridden by the VideoTrack class, because only video
4680   // keyframes can be used as seek target.
4681 
4682   return true;
4683 }
4684 
Seek(long long time_ns,const BlockEntry * & pResult) const4685 long Track::Seek(long long time_ns, const BlockEntry*& pResult) const {
4686   const long status = GetFirst(pResult);
4687 
4688   if (status < 0)  // buffer underflow, etc
4689     return status;
4690 
4691   assert(pResult);
4692 
4693   if (pResult->EOS())
4694     return 0;
4695 
4696   const Cluster* pCluster = pResult->GetCluster();
4697   assert(pCluster);
4698   assert(pCluster->GetIndex() >= 0);
4699 
4700   if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
4701     return 0;
4702 
4703   Cluster** const clusters = m_pSegment->m_clusters;
4704   assert(clusters);
4705 
4706   const long count = m_pSegment->GetCount();  // loaded only, not preloaded
4707   assert(count > 0);
4708 
4709   Cluster** const i = clusters + pCluster->GetIndex();
4710   assert(i);
4711   assert(*i == pCluster);
4712   assert(pCluster->GetTime() <= time_ns);
4713 
4714   Cluster** const j = clusters + count;
4715 
4716   Cluster** lo = i;
4717   Cluster** hi = j;
4718 
4719   while (lo < hi) {
4720     // INVARIANT:
4721     //[i, lo) <= time_ns
4722     //[lo, hi) ?
4723     //[hi, j)  > time_ns
4724 
4725     Cluster** const mid = lo + (hi - lo) / 2;
4726     assert(mid < hi);
4727 
4728     pCluster = *mid;
4729     assert(pCluster);
4730     assert(pCluster->GetIndex() >= 0);
4731     assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
4732 
4733     const long long t = pCluster->GetTime();
4734 
4735     if (t <= time_ns)
4736       lo = mid + 1;
4737     else
4738       hi = mid;
4739 
4740     assert(lo <= hi);
4741   }
4742 
4743   assert(lo == hi);
4744   assert(lo > i);
4745   assert(lo <= j);
4746 
4747   while (lo > i) {
4748     pCluster = *--lo;
4749     assert(pCluster);
4750     assert(pCluster->GetTime() <= time_ns);
4751 
4752     pResult = pCluster->GetEntry(this);
4753 
4754     if ((pResult != 0) && !pResult->EOS())
4755       return 0;
4756 
4757     // landed on empty cluster (no entries)
4758   }
4759 
4760   pResult = GetEOS();  // weird
4761   return 0;
4762 }
4763 
GetContentEncodingByIndex(unsigned long idx) const4764 const ContentEncoding* Track::GetContentEncodingByIndex(
4765     unsigned long idx) const {
4766   const ptrdiff_t count =
4767       content_encoding_entries_end_ - content_encoding_entries_;
4768   assert(count >= 0);
4769 
4770   if (idx >= static_cast<unsigned long>(count))
4771     return NULL;
4772 
4773   return content_encoding_entries_[idx];
4774 }
4775 
GetContentEncodingCount() const4776 unsigned long Track::GetContentEncodingCount() const {
4777   const ptrdiff_t count =
4778       content_encoding_entries_end_ - content_encoding_entries_;
4779   assert(count >= 0);
4780 
4781   return static_cast<unsigned long>(count);
4782 }
4783 
ParseContentEncodingsEntry(long long start,long long size)4784 long Track::ParseContentEncodingsEntry(long long start, long long size) {
4785   IMkvReader* const pReader = m_pSegment->m_pReader;
4786   assert(pReader);
4787 
4788   long long pos = start;
4789   const long long stop = start + size;
4790 
4791   // Count ContentEncoding elements.
4792   int count = 0;
4793   while (pos < stop) {
4794     long long id, size;
4795     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4796     if (status < 0)  // error
4797       return status;
4798 
4799     // pos now designates start of element
4800     if (id == 0x2240)  // ContentEncoding ID
4801       ++count;
4802 
4803     pos += size;  // consume payload
4804     assert(pos <= stop);
4805   }
4806 
4807   if (count <= 0)
4808     return -1;
4809 
4810   content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count];
4811   if (!content_encoding_entries_)
4812     return -1;
4813 
4814   content_encoding_entries_end_ = content_encoding_entries_;
4815 
4816   pos = start;
4817   while (pos < stop) {
4818     long long id, size;
4819     long status = ParseElementHeader(pReader, pos, stop, id, size);
4820     if (status < 0)  // error
4821       return status;
4822 
4823     // pos now designates start of element
4824     if (id == 0x2240) {  // ContentEncoding ID
4825       ContentEncoding* const content_encoding =
4826           new (std::nothrow) ContentEncoding();
4827       if (!content_encoding)
4828         return -1;
4829 
4830       status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
4831       if (status) {
4832         delete content_encoding;
4833         return status;
4834       }
4835 
4836       *content_encoding_entries_end_++ = content_encoding;
4837     }
4838 
4839     pos += size;  // consume payload
4840     assert(pos <= stop);
4841   }
4842 
4843   assert(pos == stop);
4844 
4845   return 0;
4846 }
4847 
EOSBlock()4848 Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
4849 
GetKind() const4850 BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
4851 
GetBlock() const4852 const Block* Track::EOSBlock::GetBlock() const { return NULL; }
4853 
VideoTrack(Segment * pSegment,long long element_start,long long element_size)4854 VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
4855                        long long element_size)
4856     : Track(pSegment, element_start, element_size) {}
4857 
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,VideoTrack * & pResult)4858 long VideoTrack::Parse(Segment* pSegment, const Info& info,
4859                        long long element_start, long long element_size,
4860                        VideoTrack*& pResult) {
4861   if (pResult)
4862     return -1;
4863 
4864   if (info.type != Track::kVideo)
4865     return -1;
4866 
4867   long long width = 0;
4868   long long height = 0;
4869   long long display_width = 0;
4870   long long display_height = 0;
4871   long long display_unit = 0;
4872   long long stereo_mode = 0;
4873 
4874   double rate = 0.0;
4875 
4876   IMkvReader* const pReader = pSegment->m_pReader;
4877 
4878   const Settings& s = info.settings;
4879   assert(s.start >= 0);
4880   assert(s.size >= 0);
4881 
4882   long long pos = s.start;
4883   assert(pos >= 0);
4884 
4885   const long long stop = pos + s.size;
4886 
4887   while (pos < stop) {
4888     long long id, size;
4889 
4890     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4891 
4892     if (status < 0)  // error
4893       return status;
4894 
4895     if (id == 0x30) {  // pixel width
4896       width = UnserializeUInt(pReader, pos, size);
4897 
4898       if (width <= 0)
4899         return E_FILE_FORMAT_INVALID;
4900     } else if (id == 0x3A) {  // pixel height
4901       height = UnserializeUInt(pReader, pos, size);
4902 
4903       if (height <= 0)
4904         return E_FILE_FORMAT_INVALID;
4905     } else if (id == 0x14B0) {  // display width
4906       display_width = UnserializeUInt(pReader, pos, size);
4907 
4908       if (display_width <= 0)
4909         return E_FILE_FORMAT_INVALID;
4910     } else if (id == 0x14BA) {  // display height
4911       display_height = UnserializeUInt(pReader, pos, size);
4912 
4913       if (display_height <= 0)
4914         return E_FILE_FORMAT_INVALID;
4915     } else if (id == 0x14B2) {  // display unit
4916       display_unit = UnserializeUInt(pReader, pos, size);
4917 
4918       if (display_unit < 0)
4919         return E_FILE_FORMAT_INVALID;
4920     } else if (id == 0x13B8) {  // stereo mode
4921       stereo_mode = UnserializeUInt(pReader, pos, size);
4922 
4923       if (stereo_mode < 0)
4924         return E_FILE_FORMAT_INVALID;
4925     } else if (id == 0x0383E3) {  // frame rate
4926       const long status = UnserializeFloat(pReader, pos, size, rate);
4927 
4928       if (status < 0)
4929         return status;
4930 
4931       if (rate <= 0)
4932         return E_FILE_FORMAT_INVALID;
4933     }
4934 
4935     pos += size;  // consume payload
4936     assert(pos <= stop);
4937   }
4938 
4939   assert(pos == stop);
4940 
4941   VideoTrack* const pTrack =
4942       new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
4943 
4944   if (pTrack == NULL)
4945     return -1;  // generic error
4946 
4947   const int status = info.Copy(pTrack->m_info);
4948 
4949   if (status) {  // error
4950     delete pTrack;
4951     return status;
4952   }
4953 
4954   pTrack->m_width = width;
4955   pTrack->m_height = height;
4956   pTrack->m_display_width = display_width;
4957   pTrack->m_display_height = display_height;
4958   pTrack->m_display_unit = display_unit;
4959   pTrack->m_stereo_mode = stereo_mode;
4960   pTrack->m_rate = rate;
4961 
4962   pResult = pTrack;
4963   return 0;  // success
4964 }
4965 
VetEntry(const BlockEntry * pBlockEntry) const4966 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
4967   return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
4968 }
4969 
Seek(long long time_ns,const BlockEntry * & pResult) const4970 long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
4971   const long status = GetFirst(pResult);
4972 
4973   if (status < 0)  // buffer underflow, etc
4974     return status;
4975 
4976   assert(pResult);
4977 
4978   if (pResult->EOS())
4979     return 0;
4980 
4981   const Cluster* pCluster = pResult->GetCluster();
4982   assert(pCluster);
4983   assert(pCluster->GetIndex() >= 0);
4984 
4985   if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
4986     return 0;
4987 
4988   Cluster** const clusters = m_pSegment->m_clusters;
4989   assert(clusters);
4990 
4991   const long count = m_pSegment->GetCount();  // loaded only, not pre-loaded
4992   assert(count > 0);
4993 
4994   Cluster** const i = clusters + pCluster->GetIndex();
4995   assert(i);
4996   assert(*i == pCluster);
4997   assert(pCluster->GetTime() <= time_ns);
4998 
4999   Cluster** const j = clusters + count;
5000 
5001   Cluster** lo = i;
5002   Cluster** hi = j;
5003 
5004   while (lo < hi) {
5005     // INVARIANT:
5006     //[i, lo) <= time_ns
5007     //[lo, hi) ?
5008     //[hi, j)  > time_ns
5009 
5010     Cluster** const mid = lo + (hi - lo) / 2;
5011     assert(mid < hi);
5012 
5013     pCluster = *mid;
5014     assert(pCluster);
5015     assert(pCluster->GetIndex() >= 0);
5016     assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5017 
5018     const long long t = pCluster->GetTime();
5019 
5020     if (t <= time_ns)
5021       lo = mid + 1;
5022     else
5023       hi = mid;
5024 
5025     assert(lo <= hi);
5026   }
5027 
5028   assert(lo == hi);
5029   assert(lo > i);
5030   assert(lo <= j);
5031 
5032   pCluster = *--lo;
5033   assert(pCluster);
5034   assert(pCluster->GetTime() <= time_ns);
5035 
5036   pResult = pCluster->GetEntry(this, time_ns);
5037 
5038   if ((pResult != 0) && !pResult->EOS())  // found a keyframe
5039     return 0;
5040 
5041   while (lo != i) {
5042     pCluster = *--lo;
5043     assert(pCluster);
5044     assert(pCluster->GetTime() <= time_ns);
5045 
5046     pResult = pCluster->GetEntry(this, time_ns);
5047 
5048     if ((pResult != 0) && !pResult->EOS())
5049       return 0;
5050   }
5051 
5052   // weird: we're on the first cluster, but no keyframe found
5053   // should never happen but we must return something anyway
5054 
5055   pResult = GetEOS();
5056   return 0;
5057 }
5058 
GetWidth() const5059 long long VideoTrack::GetWidth() const { return m_width; }
5060 
GetHeight() const5061 long long VideoTrack::GetHeight() const { return m_height; }
5062 
GetDisplayWidth() const5063 long long VideoTrack::GetDisplayWidth() const {
5064   return m_display_width > 0 ? m_display_width : GetWidth();
5065 }
5066 
GetDisplayHeight() const5067 long long VideoTrack::GetDisplayHeight() const {
5068   return m_display_height > 0 ? m_display_height : GetHeight();
5069 }
5070 
GetDisplayUnit() const5071 long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }
5072 
GetStereoMode() const5073 long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }
5074 
GetFrameRate() const5075 double VideoTrack::GetFrameRate() const { return m_rate; }
5076 
AudioTrack(Segment * pSegment,long long element_start,long long element_size)5077 AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
5078                        long long element_size)
5079     : Track(pSegment, element_start, element_size) {}
5080 
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,AudioTrack * & pResult)5081 long AudioTrack::Parse(Segment* pSegment, const Info& info,
5082                        long long element_start, long long element_size,
5083                        AudioTrack*& pResult) {
5084   if (pResult)
5085     return -1;
5086 
5087   if (info.type != Track::kAudio)
5088     return -1;
5089 
5090   IMkvReader* const pReader = pSegment->m_pReader;
5091 
5092   const Settings& s = info.settings;
5093   assert(s.start >= 0);
5094   assert(s.size >= 0);
5095 
5096   long long pos = s.start;
5097   assert(pos >= 0);
5098 
5099   const long long stop = pos + s.size;
5100 
5101   double rate = 8000.0;  // MKV default
5102   long long channels = 1;
5103   long long bit_depth = 0;
5104 
5105   while (pos < stop) {
5106     long long id, size;
5107 
5108     long status = ParseElementHeader(pReader, pos, stop, id, size);
5109 
5110     if (status < 0)  // error
5111       return status;
5112 
5113     if (id == 0x35) {  // Sample Rate
5114       status = UnserializeFloat(pReader, pos, size, rate);
5115 
5116       if (status < 0)
5117         return status;
5118 
5119       if (rate <= 0)
5120         return E_FILE_FORMAT_INVALID;
5121     } else if (id == 0x1F) {  // Channel Count
5122       channels = UnserializeUInt(pReader, pos, size);
5123 
5124       if (channels <= 0)
5125         return E_FILE_FORMAT_INVALID;
5126     } else if (id == 0x2264) {  // Bit Depth
5127       bit_depth = UnserializeUInt(pReader, pos, size);
5128 
5129       if (bit_depth <= 0)
5130         return E_FILE_FORMAT_INVALID;
5131     }
5132 
5133     pos += size;  // consume payload
5134     assert(pos <= stop);
5135   }
5136 
5137   assert(pos == stop);
5138 
5139   AudioTrack* const pTrack =
5140       new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
5141 
5142   if (pTrack == NULL)
5143     return -1;  // generic error
5144 
5145   const int status = info.Copy(pTrack->m_info);
5146 
5147   if (status) {
5148     delete pTrack;
5149     return status;
5150   }
5151 
5152   pTrack->m_rate = rate;
5153   pTrack->m_channels = channels;
5154   pTrack->m_bitDepth = bit_depth;
5155 
5156   pResult = pTrack;
5157   return 0;  // success
5158 }
5159 
GetSamplingRate() const5160 double AudioTrack::GetSamplingRate() const { return m_rate; }
5161 
GetChannels() const5162 long long AudioTrack::GetChannels() const { return m_channels; }
5163 
GetBitDepth() const5164 long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
5165 
Tracks(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)5166 Tracks::Tracks(Segment* pSegment, long long start, long long size_,
5167                long long element_start, long long element_size)
5168     : m_pSegment(pSegment),
5169       m_start(start),
5170       m_size(size_),
5171       m_element_start(element_start),
5172       m_element_size(element_size),
5173       m_trackEntries(NULL),
5174       m_trackEntriesEnd(NULL) {}
5175 
Parse()5176 long Tracks::Parse() {
5177   assert(m_trackEntries == NULL);
5178   assert(m_trackEntriesEnd == NULL);
5179 
5180   const long long stop = m_start + m_size;
5181   IMkvReader* const pReader = m_pSegment->m_pReader;
5182 
5183   int count = 0;
5184   long long pos = m_start;
5185 
5186   while (pos < stop) {
5187     long long id, size;
5188 
5189     const long status = ParseElementHeader(pReader, pos, stop, id, size);
5190 
5191     if (status < 0)  // error
5192       return status;
5193 
5194     if (size == 0)  // weird
5195       continue;
5196 
5197     if (id == 0x2E)  // TrackEntry ID
5198       ++count;
5199 
5200     pos += size;  // consume payload
5201     assert(pos <= stop);
5202   }
5203 
5204   assert(pos == stop);
5205 
5206   if (count <= 0)
5207     return 0;  // success
5208 
5209   m_trackEntries = new (std::nothrow) Track*[count];
5210 
5211   if (m_trackEntries == NULL)
5212     return -1;
5213 
5214   m_trackEntriesEnd = m_trackEntries;
5215 
5216   pos = m_start;
5217 
5218   while (pos < stop) {
5219     const long long element_start = pos;
5220 
5221     long long id, payload_size;
5222 
5223     const long status =
5224         ParseElementHeader(pReader, pos, stop, id, payload_size);
5225 
5226     if (status < 0)  // error
5227       return status;
5228 
5229     if (payload_size == 0)  // weird
5230       continue;
5231 
5232     const long long payload_stop = pos + payload_size;
5233     assert(payload_stop <= stop);  // checked in ParseElement
5234 
5235     const long long element_size = payload_stop - element_start;
5236 
5237     if (id == 0x2E) {  // TrackEntry ID
5238       Track*& pTrack = *m_trackEntriesEnd;
5239       pTrack = NULL;
5240 
5241       const long status = ParseTrackEntry(pos, payload_size, element_start,
5242                                           element_size, pTrack);
5243 
5244       if (status)
5245         return status;
5246 
5247       if (pTrack)
5248         ++m_trackEntriesEnd;
5249     }
5250 
5251     pos = payload_stop;
5252     assert(pos <= stop);
5253   }
5254 
5255   assert(pos == stop);
5256 
5257   return 0;  // success
5258 }
5259 
GetTracksCount() const5260 unsigned long Tracks::GetTracksCount() const {
5261   const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
5262   assert(result >= 0);
5263 
5264   return static_cast<unsigned long>(result);
5265 }
5266 
ParseTrackEntry(long long track_start,long long track_size,long long element_start,long long element_size,Track * & pResult) const5267 long Tracks::ParseTrackEntry(long long track_start, long long track_size,
5268                              long long element_start, long long element_size,
5269                              Track*& pResult) const {
5270   if (pResult)
5271     return -1;
5272 
5273   IMkvReader* const pReader = m_pSegment->m_pReader;
5274 
5275   long long pos = track_start;
5276   const long long track_stop = track_start + track_size;
5277 
5278   Track::Info info;
5279 
5280   info.type = 0;
5281   info.number = 0;
5282   info.uid = 0;
5283   info.defaultDuration = 0;
5284 
5285   Track::Settings v;
5286   v.start = -1;
5287   v.size = -1;
5288 
5289   Track::Settings a;
5290   a.start = -1;
5291   a.size = -1;
5292 
5293   Track::Settings e;  // content_encodings_settings;
5294   e.start = -1;
5295   e.size = -1;
5296 
5297   long long lacing = 1;  // default is true
5298 
5299   while (pos < track_stop) {
5300     long long id, size;
5301 
5302     const long status = ParseElementHeader(pReader, pos, track_stop, id, size);
5303 
5304     if (status < 0)  // error
5305       return status;
5306 
5307     if (size < 0)
5308       return E_FILE_FORMAT_INVALID;
5309 
5310     const long long start = pos;
5311 
5312     if (id == 0x60) {  // VideoSettings ID
5313       v.start = start;
5314       v.size = size;
5315     } else if (id == 0x61) {  // AudioSettings ID
5316       a.start = start;
5317       a.size = size;
5318     } else if (id == 0x2D80) {  // ContentEncodings ID
5319       e.start = start;
5320       e.size = size;
5321     } else if (id == 0x33C5) {  // Track UID
5322       if (size > 8)
5323         return E_FILE_FORMAT_INVALID;
5324 
5325       info.uid = 0;
5326 
5327       long long pos_ = start;
5328       const long long pos_end = start + size;
5329 
5330       while (pos_ != pos_end) {
5331         unsigned char b;
5332 
5333         const int status = pReader->Read(pos_, 1, &b);
5334 
5335         if (status)
5336           return status;
5337 
5338         info.uid <<= 8;
5339         info.uid |= b;
5340 
5341         ++pos_;
5342       }
5343     } else if (id == 0x57) {  // Track Number
5344       const long long num = UnserializeUInt(pReader, pos, size);
5345 
5346       if ((num <= 0) || (num > 127))
5347         return E_FILE_FORMAT_INVALID;
5348 
5349       info.number = static_cast<long>(num);
5350     } else if (id == 0x03) {  // Track Type
5351       const long long type = UnserializeUInt(pReader, pos, size);
5352 
5353       if ((type <= 0) || (type > 254))
5354         return E_FILE_FORMAT_INVALID;
5355 
5356       info.type = static_cast<long>(type);
5357     } else if (id == 0x136E) {  // Track Name
5358       const long status =
5359           UnserializeString(pReader, pos, size, info.nameAsUTF8);
5360 
5361       if (status)
5362         return status;
5363     } else if (id == 0x02B59C) {  // Track Language
5364       const long status = UnserializeString(pReader, pos, size, info.language);
5365 
5366       if (status)
5367         return status;
5368     } else if (id == 0x03E383) {  // Default Duration
5369       const long long duration = UnserializeUInt(pReader, pos, size);
5370 
5371       if (duration < 0)
5372         return E_FILE_FORMAT_INVALID;
5373 
5374       info.defaultDuration = static_cast<unsigned long long>(duration);
5375     } else if (id == 0x06) {  // CodecID
5376       const long status = UnserializeString(pReader, pos, size, info.codecId);
5377 
5378       if (status)
5379         return status;
5380     } else if (id == 0x1C) {  // lacing
5381       lacing = UnserializeUInt(pReader, pos, size);
5382 
5383       if ((lacing < 0) || (lacing > 1))
5384         return E_FILE_FORMAT_INVALID;
5385     } else if (id == 0x23A2) {  // Codec Private
5386       delete[] info.codecPrivate;
5387       info.codecPrivate = NULL;
5388       info.codecPrivateSize = 0;
5389 
5390       const size_t buflen = static_cast<size_t>(size);
5391 
5392       if (buflen) {
5393         typedef unsigned char* buf_t;
5394 
5395         const buf_t buf = new (std::nothrow) unsigned char[buflen];
5396 
5397         if (buf == NULL)
5398           return -1;
5399 
5400         const int status = pReader->Read(pos, static_cast<long>(buflen), buf);
5401 
5402         if (status) {
5403           delete[] buf;
5404           return status;
5405         }
5406 
5407         info.codecPrivate = buf;
5408         info.codecPrivateSize = buflen;
5409       }
5410     } else if (id == 0x058688) {  // Codec Name
5411       const long status =
5412           UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
5413 
5414       if (status)
5415         return status;
5416     } else if (id == 0x16AA) {  // Codec Delay
5417       info.codecDelay = UnserializeUInt(pReader, pos, size);
5418     } else if (id == 0x16BB) {  // Seek Pre Roll
5419       info.seekPreRoll = UnserializeUInt(pReader, pos, size);
5420     }
5421 
5422     pos += size;  // consume payload
5423     assert(pos <= track_stop);
5424   }
5425 
5426   assert(pos == track_stop);
5427 
5428   if (info.number <= 0)  // not specified
5429     return E_FILE_FORMAT_INVALID;
5430 
5431   if (GetTrackByNumber(info.number))
5432     return E_FILE_FORMAT_INVALID;
5433 
5434   if (info.type <= 0)  // not specified
5435     return E_FILE_FORMAT_INVALID;
5436 
5437   info.lacing = (lacing > 0) ? true : false;
5438 
5439   if (info.type == Track::kVideo) {
5440     if (v.start < 0)
5441       return E_FILE_FORMAT_INVALID;
5442 
5443     if (a.start >= 0)
5444       return E_FILE_FORMAT_INVALID;
5445 
5446     info.settings = v;
5447 
5448     VideoTrack* pTrack = NULL;
5449 
5450     const long status = VideoTrack::Parse(m_pSegment, info, element_start,
5451                                           element_size, pTrack);
5452 
5453     if (status)
5454       return status;
5455 
5456     pResult = pTrack;
5457     assert(pResult);
5458 
5459     if (e.start >= 0)
5460       pResult->ParseContentEncodingsEntry(e.start, e.size);
5461   } else if (info.type == Track::kAudio) {
5462     if (a.start < 0)
5463       return E_FILE_FORMAT_INVALID;
5464 
5465     if (v.start >= 0)
5466       return E_FILE_FORMAT_INVALID;
5467 
5468     info.settings = a;
5469 
5470     AudioTrack* pTrack = NULL;
5471 
5472     const long status = AudioTrack::Parse(m_pSegment, info, element_start,
5473                                           element_size, pTrack);
5474 
5475     if (status)
5476       return status;
5477 
5478     pResult = pTrack;
5479     assert(pResult);
5480 
5481     if (e.start >= 0)
5482       pResult->ParseContentEncodingsEntry(e.start, e.size);
5483   } else {
5484     // neither video nor audio - probably metadata or subtitles
5485 
5486     if (a.start >= 0)
5487       return E_FILE_FORMAT_INVALID;
5488 
5489     if (v.start >= 0)
5490       return E_FILE_FORMAT_INVALID;
5491 
5492     if (info.type == Track::kMetadata && e.start >= 0)
5493       return E_FILE_FORMAT_INVALID;
5494 
5495     info.settings.start = -1;
5496     info.settings.size = 0;
5497 
5498     Track* pTrack = NULL;
5499 
5500     const long status =
5501         Track::Create(m_pSegment, info, element_start, element_size, pTrack);
5502 
5503     if (status)
5504       return status;
5505 
5506     pResult = pTrack;
5507     assert(pResult);
5508   }
5509 
5510   return 0;  // success
5511 }
5512 
~Tracks()5513 Tracks::~Tracks() {
5514   Track** i = m_trackEntries;
5515   Track** const j = m_trackEntriesEnd;
5516 
5517   while (i != j) {
5518     Track* const pTrack = *i++;
5519     delete pTrack;
5520   }
5521 
5522   delete[] m_trackEntries;
5523 }
5524 
GetTrackByNumber(long tn) const5525 const Track* Tracks::GetTrackByNumber(long tn) const {
5526   if (tn < 0)
5527     return NULL;
5528 
5529   Track** i = m_trackEntries;
5530   Track** const j = m_trackEntriesEnd;
5531 
5532   while (i != j) {
5533     Track* const pTrack = *i++;
5534 
5535     if (pTrack == NULL)
5536       continue;
5537 
5538     if (tn == pTrack->GetNumber())
5539       return pTrack;
5540   }
5541 
5542   return NULL;  // not found
5543 }
5544 
GetTrackByIndex(unsigned long idx) const5545 const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
5546   const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
5547 
5548   if (idx >= static_cast<unsigned long>(count))
5549     return NULL;
5550 
5551   return m_trackEntries[idx];
5552 }
5553 
Load(long long & pos,long & len) const5554 long Cluster::Load(long long& pos, long& len) const {
5555   assert(m_pSegment);
5556   assert(m_pos >= m_element_start);
5557 
5558   if (m_timecode >= 0)  // at least partially loaded
5559     return 0;
5560 
5561   assert(m_pos == m_element_start);
5562   assert(m_element_size < 0);
5563 
5564   IMkvReader* const pReader = m_pSegment->m_pReader;
5565 
5566   long long total, avail;
5567 
5568   const int status = pReader->Length(&total, &avail);
5569 
5570   if (status < 0)  // error
5571     return status;
5572 
5573   assert((total < 0) || (avail <= total));
5574   assert((total < 0) || (m_pos <= total));  // TODO: verify this
5575 
5576   pos = m_pos;
5577 
5578   long long cluster_size = -1;
5579 
5580   {
5581     if ((pos + 1) > avail) {
5582       len = 1;
5583       return E_BUFFER_NOT_FULL;
5584     }
5585 
5586     long long result = GetUIntLength(pReader, pos, len);
5587 
5588     if (result < 0)  // error or underflow
5589       return static_cast<long>(result);
5590 
5591     if (result > 0)  // underflow (weird)
5592       return E_BUFFER_NOT_FULL;
5593 
5594     // if ((pos + len) > segment_stop)
5595     //    return E_FILE_FORMAT_INVALID;
5596 
5597     if ((pos + len) > avail)
5598       return E_BUFFER_NOT_FULL;
5599 
5600     const long long id_ = ReadUInt(pReader, pos, len);
5601 
5602     if (id_ < 0)  // error
5603       return static_cast<long>(id_);
5604 
5605     if (id_ != 0x0F43B675)  // Cluster ID
5606       return E_FILE_FORMAT_INVALID;
5607 
5608     pos += len;  // consume id
5609 
5610     // read cluster size
5611 
5612     if ((pos + 1) > avail) {
5613       len = 1;
5614       return E_BUFFER_NOT_FULL;
5615     }
5616 
5617     result = GetUIntLength(pReader, pos, len);
5618 
5619     if (result < 0)  // error
5620       return static_cast<long>(result);
5621 
5622     if (result > 0)  // weird
5623       return E_BUFFER_NOT_FULL;
5624 
5625     // if ((pos + len) > segment_stop)
5626     //    return E_FILE_FORMAT_INVALID;
5627 
5628     if ((pos + len) > avail)
5629       return E_BUFFER_NOT_FULL;
5630 
5631     const long long size = ReadUInt(pReader, pos, len);
5632 
5633     if (size < 0)  // error
5634       return static_cast<long>(cluster_size);
5635 
5636     if (size == 0)
5637       return E_FILE_FORMAT_INVALID;  // TODO: verify this
5638 
5639     pos += len;  // consume length of size of element
5640 
5641     const long long unknown_size = (1LL << (7 * len)) - 1;
5642 
5643     if (size != unknown_size)
5644       cluster_size = size;
5645   }
5646 
5647   // pos points to start of payload
5648   long long timecode = -1;
5649   long long new_pos = -1;
5650   bool bBlock = false;
5651 
5652   long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
5653 
5654   for (;;) {
5655     if ((cluster_stop >= 0) && (pos >= cluster_stop))
5656       break;
5657 
5658     // Parse ID
5659 
5660     if ((pos + 1) > avail) {
5661       len = 1;
5662       return E_BUFFER_NOT_FULL;
5663     }
5664 
5665     long long result = GetUIntLength(pReader, pos, len);
5666 
5667     if (result < 0)  // error
5668       return static_cast<long>(result);
5669 
5670     if (result > 0)  // weird
5671       return E_BUFFER_NOT_FULL;
5672 
5673     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
5674       return E_FILE_FORMAT_INVALID;
5675 
5676     if ((pos + len) > avail)
5677       return E_BUFFER_NOT_FULL;
5678 
5679     const long long id = ReadUInt(pReader, pos, len);
5680 
5681     if (id < 0)  // error
5682       return static_cast<long>(id);
5683 
5684     if (id == 0)
5685       return E_FILE_FORMAT_INVALID;
5686 
5687     // This is the distinguished set of ID's we use to determine
5688     // that we have exhausted the sub-element's inside the cluster
5689     // whose ID we parsed earlier.
5690 
5691     if (id == 0x0F43B675)  // Cluster ID
5692       break;
5693 
5694     if (id == 0x0C53BB6B)  // Cues ID
5695       break;
5696 
5697     pos += len;  // consume ID field
5698 
5699     // Parse Size
5700 
5701     if ((pos + 1) > avail) {
5702       len = 1;
5703       return E_BUFFER_NOT_FULL;
5704     }
5705 
5706     result = GetUIntLength(pReader, pos, len);
5707 
5708     if (result < 0)  // error
5709       return static_cast<long>(result);
5710 
5711     if (result > 0)  // weird
5712       return E_BUFFER_NOT_FULL;
5713 
5714     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
5715       return E_FILE_FORMAT_INVALID;
5716 
5717     if ((pos + len) > avail)
5718       return E_BUFFER_NOT_FULL;
5719 
5720     const long long size = ReadUInt(pReader, pos, len);
5721 
5722     if (size < 0)  // error
5723       return static_cast<long>(size);
5724 
5725     const long long unknown_size = (1LL << (7 * len)) - 1;
5726 
5727     if (size == unknown_size)
5728       return E_FILE_FORMAT_INVALID;
5729 
5730     pos += len;  // consume size field
5731 
5732     if ((cluster_stop >= 0) && (pos > cluster_stop))
5733       return E_FILE_FORMAT_INVALID;
5734 
5735     // pos now points to start of payload
5736 
5737     if (size == 0)  // weird
5738       continue;
5739 
5740     if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
5741       return E_FILE_FORMAT_INVALID;
5742 
5743     if (id == 0x67) {  // TimeCode ID
5744       len = static_cast<long>(size);
5745 
5746       if ((pos + size) > avail)
5747         return E_BUFFER_NOT_FULL;
5748 
5749       timecode = UnserializeUInt(pReader, pos, size);
5750 
5751       if (timecode < 0)  // error (or underflow)
5752         return static_cast<long>(timecode);
5753 
5754       new_pos = pos + size;
5755 
5756       if (bBlock)
5757         break;
5758     } else if (id == 0x20) {  // BlockGroup ID
5759       bBlock = true;
5760       break;
5761     } else if (id == 0x23) {  // SimpleBlock ID
5762       bBlock = true;
5763       break;
5764     }
5765 
5766     pos += size;  // consume payload
5767     assert((cluster_stop < 0) || (pos <= cluster_stop));
5768   }
5769 
5770   assert((cluster_stop < 0) || (pos <= cluster_stop));
5771 
5772   if (timecode < 0)  // no timecode found
5773     return E_FILE_FORMAT_INVALID;
5774 
5775   if (!bBlock)
5776     return E_FILE_FORMAT_INVALID;
5777 
5778   m_pos = new_pos;  // designates position just beyond timecode payload
5779   m_timecode = timecode;  // m_timecode >= 0 means we're partially loaded
5780 
5781   if (cluster_size >= 0)
5782     m_element_size = cluster_stop - m_element_start;
5783 
5784   return 0;
5785 }
5786 
Parse(long long & pos,long & len) const5787 long Cluster::Parse(long long& pos, long& len) const {
5788   long status = Load(pos, len);
5789 
5790   if (status < 0)
5791     return status;
5792 
5793   assert(m_pos >= m_element_start);
5794   assert(m_timecode >= 0);
5795   // assert(m_size > 0);
5796   // assert(m_element_size > m_size);
5797 
5798   const long long cluster_stop =
5799       (m_element_size < 0) ? -1 : m_element_start + m_element_size;
5800 
5801   if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
5802     return 1;  // nothing else to do
5803 
5804   IMkvReader* const pReader = m_pSegment->m_pReader;
5805 
5806   long long total, avail;
5807 
5808   status = pReader->Length(&total, &avail);
5809 
5810   if (status < 0)  // error
5811     return status;
5812 
5813   assert((total < 0) || (avail <= total));
5814 
5815   pos = m_pos;
5816 
5817   for (;;) {
5818     if ((cluster_stop >= 0) && (pos >= cluster_stop))
5819       break;
5820 
5821     if ((total >= 0) && (pos >= total)) {
5822       if (m_element_size < 0)
5823         m_element_size = pos - m_element_start;
5824 
5825       break;
5826     }
5827 
5828     // Parse ID
5829 
5830     if ((pos + 1) > avail) {
5831       len = 1;
5832       return E_BUFFER_NOT_FULL;
5833     }
5834 
5835     long long result = GetUIntLength(pReader, pos, len);
5836 
5837     if (result < 0)  // error
5838       return static_cast<long>(result);
5839 
5840     if (result > 0)  // weird
5841       return E_BUFFER_NOT_FULL;
5842 
5843     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
5844       return E_FILE_FORMAT_INVALID;
5845 
5846     if ((pos + len) > avail)
5847       return E_BUFFER_NOT_FULL;
5848 
5849     const long long id = ReadUInt(pReader, pos, len);
5850 
5851     if (id < 0)  // error
5852       return static_cast<long>(id);
5853 
5854     if (id == 0)  // weird
5855       return E_FILE_FORMAT_INVALID;
5856 
5857     // This is the distinguished set of ID's we use to determine
5858     // that we have exhausted the sub-element's inside the cluster
5859     // whose ID we parsed earlier.
5860 
5861     if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) {  // Cluster or Cues ID
5862       if (m_element_size < 0)
5863         m_element_size = pos - m_element_start;
5864 
5865       break;
5866     }
5867 
5868     pos += len;  // consume ID field
5869 
5870     // Parse Size
5871 
5872     if ((pos + 1) > avail) {
5873       len = 1;
5874       return E_BUFFER_NOT_FULL;
5875     }
5876 
5877     result = GetUIntLength(pReader, pos, len);
5878 
5879     if (result < 0)  // error
5880       return static_cast<long>(result);
5881 
5882     if (result > 0)  // weird
5883       return E_BUFFER_NOT_FULL;
5884 
5885     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
5886       return E_FILE_FORMAT_INVALID;
5887 
5888     if ((pos + len) > avail)
5889       return E_BUFFER_NOT_FULL;
5890 
5891     const long long size = ReadUInt(pReader, pos, len);
5892 
5893     if (size < 0)  // error
5894       return static_cast<long>(size);
5895 
5896     const long long unknown_size = (1LL << (7 * len)) - 1;
5897 
5898     if (size == unknown_size)
5899       return E_FILE_FORMAT_INVALID;
5900 
5901     pos += len;  // consume size field
5902 
5903     if ((cluster_stop >= 0) && (pos > cluster_stop))
5904       return E_FILE_FORMAT_INVALID;
5905 
5906     // pos now points to start of payload
5907 
5908     if (size == 0)  // weird
5909       continue;
5910 
5911     // const long long block_start = pos;
5912     const long long block_stop = pos + size;
5913 
5914     if (cluster_stop >= 0) {
5915       if (block_stop > cluster_stop) {
5916         if ((id == 0x20) || (id == 0x23))
5917           return E_FILE_FORMAT_INVALID;
5918 
5919         pos = cluster_stop;
5920         break;
5921       }
5922     } else if ((total >= 0) && (block_stop > total)) {
5923       m_element_size = total - m_element_start;
5924       pos = total;
5925       break;
5926     } else if (block_stop > avail) {
5927       len = static_cast<long>(size);
5928       return E_BUFFER_NOT_FULL;
5929     }
5930 
5931     Cluster* const this_ = const_cast<Cluster*>(this);
5932 
5933     if (id == 0x20)  // BlockGroup
5934       return this_->ParseBlockGroup(size, pos, len);
5935 
5936     if (id == 0x23)  // SimpleBlock
5937       return this_->ParseSimpleBlock(size, pos, len);
5938 
5939     pos += size;  // consume payload
5940     assert((cluster_stop < 0) || (pos <= cluster_stop));
5941   }
5942 
5943   assert(m_element_size > 0);
5944 
5945   m_pos = pos;
5946   assert((cluster_stop < 0) || (m_pos <= cluster_stop));
5947 
5948   if (m_entries_count > 0) {
5949     const long idx = m_entries_count - 1;
5950 
5951     const BlockEntry* const pLast = m_entries[idx];
5952     assert(pLast);
5953 
5954     const Block* const pBlock = pLast->GetBlock();
5955     assert(pBlock);
5956 
5957     const long long start = pBlock->m_start;
5958 
5959     if ((total >= 0) && (start > total))
5960       return -1;  // defend against trucated stream
5961 
5962     const long long size = pBlock->m_size;
5963 
5964     const long long stop = start + size;
5965     assert((cluster_stop < 0) || (stop <= cluster_stop));
5966 
5967     if ((total >= 0) && (stop > total))
5968       return -1;  // defend against trucated stream
5969   }
5970 
5971   return 1;  // no more entries
5972 }
5973 
ParseSimpleBlock(long long block_size,long long & pos,long & len)5974 long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
5975                                long& len) {
5976   const long long block_start = pos;
5977   const long long block_stop = pos + block_size;
5978 
5979   IMkvReader* const pReader = m_pSegment->m_pReader;
5980 
5981   long long total, avail;
5982 
5983   long status = pReader->Length(&total, &avail);
5984 
5985   if (status < 0)  // error
5986     return status;
5987 
5988   assert((total < 0) || (avail <= total));
5989 
5990   // parse track number
5991 
5992   if ((pos + 1) > avail) {
5993     len = 1;
5994     return E_BUFFER_NOT_FULL;
5995   }
5996 
5997   long long result = GetUIntLength(pReader, pos, len);
5998 
5999   if (result < 0)  // error
6000     return static_cast<long>(result);
6001 
6002   if (result > 0)  // weird
6003     return E_BUFFER_NOT_FULL;
6004 
6005   if ((pos + len) > block_stop)
6006     return E_FILE_FORMAT_INVALID;
6007 
6008   if ((pos + len) > avail)
6009     return E_BUFFER_NOT_FULL;
6010 
6011   const long long track = ReadUInt(pReader, pos, len);
6012 
6013   if (track < 0)  // error
6014     return static_cast<long>(track);
6015 
6016   if (track == 0)
6017     return E_FILE_FORMAT_INVALID;
6018 
6019   pos += len;  // consume track number
6020 
6021   if ((pos + 2) > block_stop)
6022     return E_FILE_FORMAT_INVALID;
6023 
6024   if ((pos + 2) > avail) {
6025     len = 2;
6026     return E_BUFFER_NOT_FULL;
6027   }
6028 
6029   pos += 2;  // consume timecode
6030 
6031   if ((pos + 1) > block_stop)
6032     return E_FILE_FORMAT_INVALID;
6033 
6034   if ((pos + 1) > avail) {
6035     len = 1;
6036     return E_BUFFER_NOT_FULL;
6037   }
6038 
6039   unsigned char flags;
6040 
6041   status = pReader->Read(pos, 1, &flags);
6042 
6043   if (status < 0) {  // error or underflow
6044     len = 1;
6045     return status;
6046   }
6047 
6048   ++pos;  // consume flags byte
6049   assert(pos <= avail);
6050 
6051   if (pos >= block_stop)
6052     return E_FILE_FORMAT_INVALID;
6053 
6054   const int lacing = int(flags & 0x06) >> 1;
6055 
6056   if ((lacing != 0) && (block_stop > avail)) {
6057     len = static_cast<long>(block_stop - pos);
6058     return E_BUFFER_NOT_FULL;
6059   }
6060 
6061   status = CreateBlock(0x23,  // simple block id
6062                        block_start, block_size,
6063                        0);  // DiscardPadding
6064 
6065   if (status != 0)
6066     return status;
6067 
6068   m_pos = block_stop;
6069 
6070   return 0;  // success
6071 }
6072 
ParseBlockGroup(long long payload_size,long long & pos,long & len)6073 long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
6074                               long& len) {
6075   const long long payload_start = pos;
6076   const long long payload_stop = pos + payload_size;
6077 
6078   IMkvReader* const pReader = m_pSegment->m_pReader;
6079 
6080   long long total, avail;
6081 
6082   long status = pReader->Length(&total, &avail);
6083 
6084   if (status < 0)  // error
6085     return status;
6086 
6087   assert((total < 0) || (avail <= total));
6088 
6089   if ((total >= 0) && (payload_stop > total))
6090     return E_FILE_FORMAT_INVALID;
6091 
6092   if (payload_stop > avail) {
6093     len = static_cast<long>(payload_size);
6094     return E_BUFFER_NOT_FULL;
6095   }
6096 
6097   long long discard_padding = 0;
6098 
6099   while (pos < payload_stop) {
6100     // parse sub-block element ID
6101 
6102     if ((pos + 1) > avail) {
6103       len = 1;
6104       return E_BUFFER_NOT_FULL;
6105     }
6106 
6107     long long result = GetUIntLength(pReader, pos, len);
6108 
6109     if (result < 0)  // error
6110       return static_cast<long>(result);
6111 
6112     if (result > 0)  // weird
6113       return E_BUFFER_NOT_FULL;
6114 
6115     if ((pos + len) > payload_stop)
6116       return E_FILE_FORMAT_INVALID;
6117 
6118     if ((pos + len) > avail)
6119       return E_BUFFER_NOT_FULL;
6120 
6121     const long long id = ReadUInt(pReader, pos, len);
6122 
6123     if (id < 0)  // error
6124       return static_cast<long>(id);
6125 
6126     if (id == 0)  // not a value ID
6127       return E_FILE_FORMAT_INVALID;
6128 
6129     pos += len;  // consume ID field
6130 
6131     // Parse Size
6132 
6133     if ((pos + 1) > avail) {
6134       len = 1;
6135       return E_BUFFER_NOT_FULL;
6136     }
6137 
6138     result = GetUIntLength(pReader, pos, len);
6139 
6140     if (result < 0)  // error
6141       return static_cast<long>(result);
6142 
6143     if (result > 0)  // weird
6144       return E_BUFFER_NOT_FULL;
6145 
6146     if ((pos + len) > payload_stop)
6147       return E_FILE_FORMAT_INVALID;
6148 
6149     if ((pos + len) > avail)
6150       return E_BUFFER_NOT_FULL;
6151 
6152     const long long size = ReadUInt(pReader, pos, len);
6153 
6154     if (size < 0)  // error
6155       return static_cast<long>(size);
6156 
6157     pos += len;  // consume size field
6158 
6159     // pos now points to start of sub-block group payload
6160 
6161     if (pos > payload_stop)
6162       return E_FILE_FORMAT_INVALID;
6163 
6164     if (size == 0)  // weird
6165       continue;
6166 
6167     const long long unknown_size = (1LL << (7 * len)) - 1;
6168 
6169     if (size == unknown_size)
6170       return E_FILE_FORMAT_INVALID;
6171 
6172     if (id == 0x35A2) {  // DiscardPadding
6173       status = UnserializeInt(pReader, pos, size, discard_padding);
6174 
6175       if (status < 0)  // error
6176         return status;
6177     }
6178 
6179     if (id != 0x21) {  // sub-part of BlockGroup is not a Block
6180       pos += size;  // consume sub-part of block group
6181 
6182       if (pos > payload_stop)
6183         return E_FILE_FORMAT_INVALID;
6184 
6185       continue;
6186     }
6187 
6188     const long long block_stop = pos + size;
6189 
6190     if (block_stop > payload_stop)
6191       return E_FILE_FORMAT_INVALID;
6192 
6193     // parse track number
6194 
6195     if ((pos + 1) > avail) {
6196       len = 1;
6197       return E_BUFFER_NOT_FULL;
6198     }
6199 
6200     result = GetUIntLength(pReader, pos, len);
6201 
6202     if (result < 0)  // error
6203       return static_cast<long>(result);
6204 
6205     if (result > 0)  // weird
6206       return E_BUFFER_NOT_FULL;
6207 
6208     if ((pos + len) > block_stop)
6209       return E_FILE_FORMAT_INVALID;
6210 
6211     if ((pos + len) > avail)
6212       return E_BUFFER_NOT_FULL;
6213 
6214     const long long track = ReadUInt(pReader, pos, len);
6215 
6216     if (track < 0)  // error
6217       return static_cast<long>(track);
6218 
6219     if (track == 0)
6220       return E_FILE_FORMAT_INVALID;
6221 
6222     pos += len;  // consume track number
6223 
6224     if ((pos + 2) > block_stop)
6225       return E_FILE_FORMAT_INVALID;
6226 
6227     if ((pos + 2) > avail) {
6228       len = 2;
6229       return E_BUFFER_NOT_FULL;
6230     }
6231 
6232     pos += 2;  // consume timecode
6233 
6234     if ((pos + 1) > block_stop)
6235       return E_FILE_FORMAT_INVALID;
6236 
6237     if ((pos + 1) > avail) {
6238       len = 1;
6239       return E_BUFFER_NOT_FULL;
6240     }
6241 
6242     unsigned char flags;
6243 
6244     status = pReader->Read(pos, 1, &flags);
6245 
6246     if (status < 0) {  // error or underflow
6247       len = 1;
6248       return status;
6249     }
6250 
6251     ++pos;  // consume flags byte
6252     assert(pos <= avail);
6253 
6254     if (pos >= block_stop)
6255       return E_FILE_FORMAT_INVALID;
6256 
6257     const int lacing = int(flags & 0x06) >> 1;
6258 
6259     if ((lacing != 0) && (block_stop > avail)) {
6260       len = static_cast<long>(block_stop - pos);
6261       return E_BUFFER_NOT_FULL;
6262     }
6263 
6264     pos = block_stop;  // consume block-part of block group
6265     assert(pos <= payload_stop);
6266   }
6267 
6268   assert(pos == payload_stop);
6269 
6270   status = CreateBlock(0x20,  // BlockGroup ID
6271                        payload_start, payload_size, discard_padding);
6272   if (status != 0)
6273     return status;
6274 
6275   m_pos = payload_stop;
6276 
6277   return 0;  // success
6278 }
6279 
GetEntry(long index,const mkvparser::BlockEntry * & pEntry) const6280 long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
6281   assert(m_pos >= m_element_start);
6282 
6283   pEntry = NULL;
6284 
6285   if (index < 0)
6286     return -1;  // generic error
6287 
6288   if (m_entries_count < 0)
6289     return E_BUFFER_NOT_FULL;
6290 
6291   assert(m_entries);
6292   assert(m_entries_size > 0);
6293   assert(m_entries_count <= m_entries_size);
6294 
6295   if (index < m_entries_count) {
6296     pEntry = m_entries[index];
6297     assert(pEntry);
6298 
6299     return 1;  // found entry
6300   }
6301 
6302   if (m_element_size < 0)  // we don't know cluster end yet
6303     return E_BUFFER_NOT_FULL;  // underflow
6304 
6305   const long long element_stop = m_element_start + m_element_size;
6306 
6307   if (m_pos >= element_stop)
6308     return 0;  // nothing left to parse
6309 
6310   return E_BUFFER_NOT_FULL;  // underflow, since more remains to be parsed
6311 }
6312 
Create(Segment * pSegment,long idx,long long off)6313 Cluster* Cluster::Create(Segment* pSegment, long idx, long long off)
6314 // long long element_size)
6315 {
6316   assert(pSegment);
6317   assert(off >= 0);
6318 
6319   const long long element_start = pSegment->m_start + off;
6320 
6321   Cluster* const pCluster = new Cluster(pSegment, idx, element_start);
6322   // element_size);
6323   assert(pCluster);
6324 
6325   return pCluster;
6326 }
6327 
Cluster()6328 Cluster::Cluster()
6329     : m_pSegment(NULL),
6330       m_element_start(0),
6331       m_index(0),
6332       m_pos(0),
6333       m_element_size(0),
6334       m_timecode(0),
6335       m_entries(NULL),
6336       m_entries_size(0),
6337       m_entries_count(0)  // means "no entries"
6338 {}
6339 
Cluster(Segment * pSegment,long idx,long long element_start)6340 Cluster::Cluster(Segment* pSegment, long idx, long long element_start
6341                  /* long long element_size */)
6342     : m_pSegment(pSegment),
6343       m_element_start(element_start),
6344       m_index(idx),
6345       m_pos(element_start),
6346       m_element_size(-1 /* element_size */),
6347       m_timecode(-1),
6348       m_entries(NULL),
6349       m_entries_size(0),
6350       m_entries_count(-1)  // means "has not been parsed yet"
6351 {}
6352 
~Cluster()6353 Cluster::~Cluster() {
6354   if (m_entries_count <= 0)
6355     return;
6356 
6357   BlockEntry** i = m_entries;
6358   BlockEntry** const j = m_entries + m_entries_count;
6359 
6360   while (i != j) {
6361     BlockEntry* p = *i++;
6362     assert(p);
6363 
6364     delete p;
6365   }
6366 
6367   delete[] m_entries;
6368 }
6369 
EOS() const6370 bool Cluster::EOS() const { return (m_pSegment == NULL); }
6371 
GetIndex() const6372 long Cluster::GetIndex() const { return m_index; }
6373 
GetPosition() const6374 long long Cluster::GetPosition() const {
6375   const long long pos = m_element_start - m_pSegment->m_start;
6376   assert(pos >= 0);
6377 
6378   return pos;
6379 }
6380 
GetElementSize() const6381 long long Cluster::GetElementSize() const { return m_element_size; }
6382 
HasBlockEntries(const Segment * pSegment,long long off,long long & pos,long & len)6383 long Cluster::HasBlockEntries(
6384     const Segment* pSegment,
6385     long long off,  // relative to start of segment payload
6386     long long& pos, long& len) {
6387   assert(pSegment);
6388   assert(off >= 0);  // relative to segment
6389 
6390   IMkvReader* const pReader = pSegment->m_pReader;
6391 
6392   long long total, avail;
6393 
6394   long status = pReader->Length(&total, &avail);
6395 
6396   if (status < 0)  // error
6397     return status;
6398 
6399   assert((total < 0) || (avail <= total));
6400 
6401   pos = pSegment->m_start + off;  // absolute
6402 
6403   if ((total >= 0) && (pos >= total))
6404     return 0;  // we don't even have a complete cluster
6405 
6406   const long long segment_stop =
6407       (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
6408 
6409   long long cluster_stop = -1;  // interpreted later to mean "unknown size"
6410 
6411   {
6412     if ((pos + 1) > avail) {
6413       len = 1;
6414       return E_BUFFER_NOT_FULL;
6415     }
6416 
6417     long long result = GetUIntLength(pReader, pos, len);
6418 
6419     if (result < 0)  // error
6420       return static_cast<long>(result);
6421 
6422     if (result > 0)  // need more data
6423       return E_BUFFER_NOT_FULL;
6424 
6425     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
6426       return E_FILE_FORMAT_INVALID;
6427 
6428     if ((total >= 0) && ((pos + len) > total))
6429       return 0;
6430 
6431     if ((pos + len) > avail)
6432       return E_BUFFER_NOT_FULL;
6433 
6434     const long long id = ReadUInt(pReader, pos, len);
6435 
6436     if (id < 0)  // error
6437       return static_cast<long>(id);
6438 
6439     if (id != 0x0F43B675)  // weird: not cluster ID
6440       return -1;  // generic error
6441 
6442     pos += len;  // consume Cluster ID field
6443 
6444     // read size field
6445 
6446     if ((pos + 1) > avail) {
6447       len = 1;
6448       return E_BUFFER_NOT_FULL;
6449     }
6450 
6451     result = GetUIntLength(pReader, pos, len);
6452 
6453     if (result < 0)  // error
6454       return static_cast<long>(result);
6455 
6456     if (result > 0)  // weird
6457       return E_BUFFER_NOT_FULL;
6458 
6459     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
6460       return E_FILE_FORMAT_INVALID;
6461 
6462     if ((total >= 0) && ((pos + len) > total))
6463       return 0;
6464 
6465     if ((pos + len) > avail)
6466       return E_BUFFER_NOT_FULL;
6467 
6468     const long long size = ReadUInt(pReader, pos, len);
6469 
6470     if (size < 0)  // error
6471       return static_cast<long>(size);
6472 
6473     if (size == 0)
6474       return 0;  // cluster does not have entries
6475 
6476     pos += len;  // consume size field
6477 
6478     // pos now points to start of payload
6479 
6480     const long long unknown_size = (1LL << (7 * len)) - 1;
6481 
6482     if (size != unknown_size) {
6483       cluster_stop = pos + size;
6484       assert(cluster_stop >= 0);
6485 
6486       if ((segment_stop >= 0) && (cluster_stop > segment_stop))
6487         return E_FILE_FORMAT_INVALID;
6488 
6489       if ((total >= 0) && (cluster_stop > total))
6490         // return E_FILE_FORMAT_INVALID;  //too conservative
6491         return 0;  // cluster does not have any entries
6492     }
6493   }
6494 
6495   for (;;) {
6496     if ((cluster_stop >= 0) && (pos >= cluster_stop))
6497       return 0;  // no entries detected
6498 
6499     if ((pos + 1) > avail) {
6500       len = 1;
6501       return E_BUFFER_NOT_FULL;
6502     }
6503 
6504     long long result = GetUIntLength(pReader, pos, len);
6505 
6506     if (result < 0)  // error
6507       return static_cast<long>(result);
6508 
6509     if (result > 0)  // need more data
6510       return E_BUFFER_NOT_FULL;
6511 
6512     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6513       return E_FILE_FORMAT_INVALID;
6514 
6515     if ((pos + len) > avail)
6516       return E_BUFFER_NOT_FULL;
6517 
6518     const long long id = ReadUInt(pReader, pos, len);
6519 
6520     if (id < 0)  // error
6521       return static_cast<long>(id);
6522 
6523     // This is the distinguished set of ID's we use to determine
6524     // that we have exhausted the sub-element's inside the cluster
6525     // whose ID we parsed earlier.
6526 
6527     if (id == 0x0F43B675)  // Cluster ID
6528       return 0;  // no entries found
6529 
6530     if (id == 0x0C53BB6B)  // Cues ID
6531       return 0;  // no entries found
6532 
6533     pos += len;  // consume id field
6534 
6535     if ((cluster_stop >= 0) && (pos >= cluster_stop))
6536       return E_FILE_FORMAT_INVALID;
6537 
6538     // read size field
6539 
6540     if ((pos + 1) > avail) {
6541       len = 1;
6542       return E_BUFFER_NOT_FULL;
6543     }
6544 
6545     result = GetUIntLength(pReader, pos, len);
6546 
6547     if (result < 0)  // error
6548       return static_cast<long>(result);
6549 
6550     if (result > 0)  // underflow
6551       return E_BUFFER_NOT_FULL;
6552 
6553     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6554       return E_FILE_FORMAT_INVALID;
6555 
6556     if ((pos + len) > avail)
6557       return E_BUFFER_NOT_FULL;
6558 
6559     const long long size = ReadUInt(pReader, pos, len);
6560 
6561     if (size < 0)  // error
6562       return static_cast<long>(size);
6563 
6564     pos += len;  // consume size field
6565 
6566     // pos now points to start of payload
6567 
6568     if ((cluster_stop >= 0) && (pos > cluster_stop))
6569       return E_FILE_FORMAT_INVALID;
6570 
6571     if (size == 0)  // weird
6572       continue;
6573 
6574     const long long unknown_size = (1LL << (7 * len)) - 1;
6575 
6576     if (size == unknown_size)
6577       return E_FILE_FORMAT_INVALID;  // not supported inside cluster
6578 
6579     if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
6580       return E_FILE_FORMAT_INVALID;
6581 
6582     if (id == 0x20)  // BlockGroup ID
6583       return 1;  // have at least one entry
6584 
6585     if (id == 0x23)  // SimpleBlock ID
6586       return 1;  // have at least one entry
6587 
6588     pos += size;  // consume payload
6589     assert((cluster_stop < 0) || (pos <= cluster_stop));
6590   }
6591 }
6592 
GetTimeCode() const6593 long long Cluster::GetTimeCode() const {
6594   long long pos;
6595   long len;
6596 
6597   const long status = Load(pos, len);
6598 
6599   if (status < 0)  // error
6600     return status;
6601 
6602   return m_timecode;
6603 }
6604 
GetTime() const6605 long long Cluster::GetTime() const {
6606   const long long tc = GetTimeCode();
6607 
6608   if (tc < 0)
6609     return tc;
6610 
6611   const SegmentInfo* const pInfo = m_pSegment->GetInfo();
6612   assert(pInfo);
6613 
6614   const long long scale = pInfo->GetTimeCodeScale();
6615   assert(scale >= 1);
6616 
6617   const long long t = m_timecode * scale;
6618 
6619   return t;
6620 }
6621 
GetFirstTime() const6622 long long Cluster::GetFirstTime() const {
6623   const BlockEntry* pEntry;
6624 
6625   const long status = GetFirst(pEntry);
6626 
6627   if (status < 0)  // error
6628     return status;
6629 
6630   if (pEntry == NULL)  // empty cluster
6631     return GetTime();
6632 
6633   const Block* const pBlock = pEntry->GetBlock();
6634   assert(pBlock);
6635 
6636   return pBlock->GetTime(this);
6637 }
6638 
GetLastTime() const6639 long long Cluster::GetLastTime() const {
6640   const BlockEntry* pEntry;
6641 
6642   const long status = GetLast(pEntry);
6643 
6644   if (status < 0)  // error
6645     return status;
6646 
6647   if (pEntry == NULL)  // empty cluster
6648     return GetTime();
6649 
6650   const Block* const pBlock = pEntry->GetBlock();
6651   assert(pBlock);
6652 
6653   return pBlock->GetTime(this);
6654 }
6655 
CreateBlock(long long id,long long pos,long long size,long long discard_padding)6656 long Cluster::CreateBlock(long long id,
6657                           long long pos,  // absolute pos of payload
6658                           long long size, long long discard_padding) {
6659   assert((id == 0x20) || (id == 0x23));  // BlockGroup or SimpleBlock
6660 
6661   if (m_entries_count < 0) {  // haven't parsed anything yet
6662     assert(m_entries == NULL);
6663     assert(m_entries_size == 0);
6664 
6665     m_entries_size = 1024;
6666     m_entries = new BlockEntry*[m_entries_size];
6667 
6668     m_entries_count = 0;
6669   } else {
6670     assert(m_entries);
6671     assert(m_entries_size > 0);
6672     assert(m_entries_count <= m_entries_size);
6673 
6674     if (m_entries_count >= m_entries_size) {
6675       const long entries_size = 2 * m_entries_size;
6676 
6677       BlockEntry** const entries = new BlockEntry*[entries_size];
6678       assert(entries);
6679 
6680       BlockEntry** src = m_entries;
6681       BlockEntry** const src_end = src + m_entries_count;
6682 
6683       BlockEntry** dst = entries;
6684 
6685       while (src != src_end)
6686         *dst++ = *src++;
6687 
6688       delete[] m_entries;
6689 
6690       m_entries = entries;
6691       m_entries_size = entries_size;
6692     }
6693   }
6694 
6695   if (id == 0x20)  // BlockGroup ID
6696     return CreateBlockGroup(pos, size, discard_padding);
6697   else  // SimpleBlock ID
6698     return CreateSimpleBlock(pos, size);
6699 }
6700 
CreateBlockGroup(long long start_offset,long long size,long long discard_padding)6701 long Cluster::CreateBlockGroup(long long start_offset, long long size,
6702                                long long discard_padding) {
6703   assert(m_entries);
6704   assert(m_entries_size > 0);
6705   assert(m_entries_count >= 0);
6706   assert(m_entries_count < m_entries_size);
6707 
6708   IMkvReader* const pReader = m_pSegment->m_pReader;
6709 
6710   long long pos = start_offset;
6711   const long long stop = start_offset + size;
6712 
6713   // For WebM files, there is a bias towards previous reference times
6714   //(in order to support alt-ref frames, which refer back to the previous
6715   // keyframe).  Normally a 0 value is not possible, but here we tenatively
6716   // allow 0 as the value of a reference frame, with the interpretation
6717   // that this is a "previous" reference time.
6718 
6719   long long prev = 1;  // nonce
6720   long long next = 0;  // nonce
6721   long long duration = -1;  // really, this is unsigned
6722 
6723   long long bpos = -1;
6724   long long bsize = -1;
6725 
6726   while (pos < stop) {
6727     long len;
6728     const long long id = ReadUInt(pReader, pos, len);
6729     assert(id >= 0);  // TODO
6730     assert((pos + len) <= stop);
6731 
6732     pos += len;  // consume ID
6733 
6734     const long long size = ReadUInt(pReader, pos, len);
6735     assert(size >= 0);  // TODO
6736     assert((pos + len) <= stop);
6737 
6738     pos += len;  // consume size
6739 
6740     if (id == 0x21) {  // Block ID
6741       if (bpos < 0) {  // Block ID
6742         bpos = pos;
6743         bsize = size;
6744       }
6745     } else if (id == 0x1B) {  // Duration ID
6746       if (size > 8)
6747         return E_FILE_FORMAT_INVALID;
6748 
6749       duration = UnserializeUInt(pReader, pos, size);
6750 
6751       if (duration < 0)
6752         return E_FILE_FORMAT_INVALID;
6753     } else if (id == 0x7B) {  // ReferenceBlock
6754       if (size > 8 || size <= 0)
6755         return E_FILE_FORMAT_INVALID;
6756       const long size_ = static_cast<long>(size);
6757 
6758       long long time;
6759 
6760       long status = UnserializeInt(pReader, pos, size_, time);
6761       assert(status == 0);
6762       if (status != 0)
6763         return -1;
6764 
6765       if (time <= 0)  // see note above
6766         prev = time;
6767       else  // weird
6768         next = time;
6769     }
6770 
6771     pos += size;  // consume payload
6772     assert(pos <= stop);
6773   }
6774   if (bpos < 0)
6775     return E_FILE_FORMAT_INVALID;
6776 
6777   assert(pos == stop);
6778   assert(bsize >= 0);
6779 
6780   const long idx = m_entries_count;
6781 
6782   BlockEntry** const ppEntry = m_entries + idx;
6783   BlockEntry*& pEntry = *ppEntry;
6784 
6785   pEntry = new (std::nothrow)
6786       BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
6787 
6788   if (pEntry == NULL)
6789     return -1;  // generic error
6790 
6791   BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
6792 
6793   const long status = p->Parse();
6794 
6795   if (status == 0) {  // success
6796     ++m_entries_count;
6797     return 0;
6798   }
6799 
6800   delete pEntry;
6801   pEntry = 0;
6802 
6803   return status;
6804 }
6805 
CreateSimpleBlock(long long st,long long sz)6806 long Cluster::CreateSimpleBlock(long long st, long long sz) {
6807   assert(m_entries);
6808   assert(m_entries_size > 0);
6809   assert(m_entries_count >= 0);
6810   assert(m_entries_count < m_entries_size);
6811 
6812   const long idx = m_entries_count;
6813 
6814   BlockEntry** const ppEntry = m_entries + idx;
6815   BlockEntry*& pEntry = *ppEntry;
6816 
6817   pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
6818 
6819   if (pEntry == NULL)
6820     return -1;  // generic error
6821 
6822   SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
6823 
6824   const long status = p->Parse();
6825 
6826   if (status == 0) {
6827     ++m_entries_count;
6828     return 0;
6829   }
6830 
6831   delete pEntry;
6832   pEntry = 0;
6833 
6834   return status;
6835 }
6836 
GetFirst(const BlockEntry * & pFirst) const6837 long Cluster::GetFirst(const BlockEntry*& pFirst) const {
6838   if (m_entries_count <= 0) {
6839     long long pos;
6840     long len;
6841 
6842     const long status = Parse(pos, len);
6843 
6844     if (status < 0) {  // error
6845       pFirst = NULL;
6846       return status;
6847     }
6848 
6849     if (m_entries_count <= 0) {  // empty cluster
6850       pFirst = NULL;
6851       return 0;
6852     }
6853   }
6854 
6855   assert(m_entries);
6856 
6857   pFirst = m_entries[0];
6858   assert(pFirst);
6859 
6860   return 0;  // success
6861 }
6862 
GetLast(const BlockEntry * & pLast) const6863 long Cluster::GetLast(const BlockEntry*& pLast) const {
6864   for (;;) {
6865     long long pos;
6866     long len;
6867 
6868     const long status = Parse(pos, len);
6869 
6870     if (status < 0) {  // error
6871       pLast = NULL;
6872       return status;
6873     }
6874 
6875     if (status > 0)  // no new block
6876       break;
6877   }
6878 
6879   if (m_entries_count <= 0) {
6880     pLast = NULL;
6881     return 0;
6882   }
6883 
6884   assert(m_entries);
6885 
6886   const long idx = m_entries_count - 1;
6887 
6888   pLast = m_entries[idx];
6889   assert(pLast);
6890 
6891   return 0;
6892 }
6893 
GetNext(const BlockEntry * pCurr,const BlockEntry * & pNext) const6894 long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const {
6895   assert(pCurr);
6896   assert(m_entries);
6897   assert(m_entries_count > 0);
6898 
6899   size_t idx = pCurr->GetIndex();
6900   assert(idx < size_t(m_entries_count));
6901   assert(m_entries[idx] == pCurr);
6902 
6903   ++idx;
6904 
6905   if (idx >= size_t(m_entries_count)) {
6906     long long pos;
6907     long len;
6908 
6909     const long status = Parse(pos, len);
6910 
6911     if (status < 0) {  // error
6912       pNext = NULL;
6913       return status;
6914     }
6915 
6916     if (status > 0) {
6917       pNext = NULL;
6918       return 0;
6919     }
6920 
6921     assert(m_entries);
6922     assert(m_entries_count > 0);
6923     assert(idx < size_t(m_entries_count));
6924   }
6925 
6926   pNext = m_entries[idx];
6927   assert(pNext);
6928 
6929   return 0;
6930 }
6931 
GetEntryCount() const6932 long Cluster::GetEntryCount() const { return m_entries_count; }
6933 
GetEntry(const Track * pTrack,long long time_ns) const6934 const BlockEntry* Cluster::GetEntry(const Track* pTrack,
6935                                     long long time_ns) const {
6936   assert(pTrack);
6937 
6938   if (m_pSegment == NULL)  // this is the special EOS cluster
6939     return pTrack->GetEOS();
6940 
6941   const BlockEntry* pResult = pTrack->GetEOS();
6942 
6943   long index = 0;
6944 
6945   for (;;) {
6946     if (index >= m_entries_count) {
6947       long long pos;
6948       long len;
6949 
6950       const long status = Parse(pos, len);
6951       assert(status >= 0);
6952 
6953       if (status > 0)  // completely parsed, and no more entries
6954         return pResult;
6955 
6956       if (status < 0)  // should never happen
6957         return 0;
6958 
6959       assert(m_entries);
6960       assert(index < m_entries_count);
6961     }
6962 
6963     const BlockEntry* const pEntry = m_entries[index];
6964     assert(pEntry);
6965     assert(!pEntry->EOS());
6966 
6967     const Block* const pBlock = pEntry->GetBlock();
6968     assert(pBlock);
6969 
6970     if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
6971       ++index;
6972       continue;
6973     }
6974 
6975     if (pTrack->VetEntry(pEntry)) {
6976       if (time_ns < 0)  // just want first candidate block
6977         return pEntry;
6978 
6979       const long long ns = pBlock->GetTime(this);
6980 
6981       if (ns > time_ns)
6982         return pResult;
6983 
6984       pResult = pEntry;  // have a candidate
6985     } else if (time_ns >= 0) {
6986       const long long ns = pBlock->GetTime(this);
6987 
6988       if (ns > time_ns)
6989         return pResult;
6990     }
6991 
6992     ++index;
6993   }
6994 }
6995 
GetEntry(const CuePoint & cp,const CuePoint::TrackPosition & tp) const6996 const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
6997                                     const CuePoint::TrackPosition& tp) const {
6998   assert(m_pSegment);
6999   const long long tc = cp.GetTimeCode();
7000 
7001   if (tp.m_block > 0) {
7002     const long block = static_cast<long>(tp.m_block);
7003     const long index = block - 1;
7004 
7005     while (index >= m_entries_count) {
7006       long long pos;
7007       long len;
7008 
7009       const long status = Parse(pos, len);
7010 
7011       if (status < 0)  // TODO: can this happen?
7012         return NULL;
7013 
7014       if (status > 0)  // nothing remains to be parsed
7015         return NULL;
7016     }
7017 
7018     const BlockEntry* const pEntry = m_entries[index];
7019     assert(pEntry);
7020     assert(!pEntry->EOS());
7021 
7022     const Block* const pBlock = pEntry->GetBlock();
7023     assert(pBlock);
7024 
7025     if ((pBlock->GetTrackNumber() == tp.m_track) &&
7026         (pBlock->GetTimeCode(this) == tc)) {
7027       return pEntry;
7028     }
7029   }
7030 
7031   long index = 0;
7032 
7033   for (;;) {
7034     if (index >= m_entries_count) {
7035       long long pos;
7036       long len;
7037 
7038       const long status = Parse(pos, len);
7039 
7040       if (status < 0)  // TODO: can this happen?
7041         return NULL;
7042 
7043       if (status > 0)  // nothing remains to be parsed
7044         return NULL;
7045 
7046       assert(m_entries);
7047       assert(index < m_entries_count);
7048     }
7049 
7050     const BlockEntry* const pEntry = m_entries[index];
7051     assert(pEntry);
7052     assert(!pEntry->EOS());
7053 
7054     const Block* const pBlock = pEntry->GetBlock();
7055     assert(pBlock);
7056 
7057     if (pBlock->GetTrackNumber() != tp.m_track) {
7058       ++index;
7059       continue;
7060     }
7061 
7062     const long long tc_ = pBlock->GetTimeCode(this);
7063 
7064     if (tc_ < tc) {
7065       ++index;
7066       continue;
7067     }
7068 
7069     if (tc_ > tc)
7070       return NULL;
7071 
7072     const Tracks* const pTracks = m_pSegment->GetTracks();
7073     assert(pTracks);
7074 
7075     const long tn = static_cast<long>(tp.m_track);
7076     const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7077 
7078     if (pTrack == NULL)
7079       return NULL;
7080 
7081     const long long type = pTrack->GetType();
7082 
7083     if (type == 2)  // audio
7084       return pEntry;
7085 
7086     if (type != 1)  // not video
7087       return NULL;
7088 
7089     if (!pBlock->IsKey())
7090       return NULL;
7091 
7092     return pEntry;
7093   }
7094 }
7095 
BlockEntry(Cluster * p,long idx)7096 BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
~BlockEntry()7097 BlockEntry::~BlockEntry() {}
EOS() const7098 bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); }
GetCluster() const7099 const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
GetIndex() const7100 long BlockEntry::GetIndex() const { return m_index; }
7101 
SimpleBlock(Cluster * pCluster,long idx,long long start,long long size)7102 SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
7103                          long long size)
7104     : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
7105 
Parse()7106 long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
GetKind() const7107 BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
GetBlock() const7108 const Block* SimpleBlock::GetBlock() const { return &m_block; }
7109 
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)7110 BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start,
7111                        long long block_size, long long prev, long long next,
7112                        long long duration, long long discard_padding)
7113     : BlockEntry(pCluster, idx),
7114       m_block(block_start, block_size, discard_padding),
7115       m_prev(prev),
7116       m_next(next),
7117       m_duration(duration) {}
7118 
Parse()7119 long BlockGroup::Parse() {
7120   const long status = m_block.Parse(m_pCluster);
7121 
7122   if (status)
7123     return status;
7124 
7125   m_block.SetKey((m_prev > 0) && (m_next <= 0));
7126 
7127   return 0;
7128 }
7129 
GetKind() const7130 BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
GetBlock() const7131 const Block* BlockGroup::GetBlock() const { return &m_block; }
GetPrevTimeCode() const7132 long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
GetNextTimeCode() const7133 long long BlockGroup::GetNextTimeCode() const { return m_next; }
GetDurationTimeCode() const7134 long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
7135 
Block(long long start,long long size_,long long discard_padding)7136 Block::Block(long long start, long long size_, long long discard_padding)
7137     : m_start(start),
7138       m_size(size_),
7139       m_track(0),
7140       m_timecode(-1),
7141       m_flags(0),
7142       m_frames(NULL),
7143       m_frame_count(-1),
7144       m_discard_padding(discard_padding) {}
7145 
~Block()7146 Block::~Block() { delete[] m_frames; }
7147 
Parse(const Cluster * pCluster)7148 long Block::Parse(const Cluster* pCluster) {
7149   if (pCluster == NULL)
7150     return -1;
7151 
7152   if (pCluster->m_pSegment == NULL)
7153     return -1;
7154 
7155   assert(m_start >= 0);
7156   assert(m_size >= 0);
7157   assert(m_track <= 0);
7158   assert(m_frames == NULL);
7159   assert(m_frame_count <= 0);
7160 
7161   long long pos = m_start;
7162   const long long stop = m_start + m_size;
7163 
7164   long len;
7165 
7166   IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;
7167 
7168   m_track = ReadUInt(pReader, pos, len);
7169 
7170   if (m_track <= 0)
7171     return E_FILE_FORMAT_INVALID;
7172 
7173   if ((pos + len) > stop)
7174     return E_FILE_FORMAT_INVALID;
7175 
7176   pos += len;  // consume track number
7177 
7178   if ((stop - pos) < 2)
7179     return E_FILE_FORMAT_INVALID;
7180 
7181   long status;
7182   long long value;
7183 
7184   status = UnserializeInt(pReader, pos, 2, value);
7185 
7186   if (status)
7187     return E_FILE_FORMAT_INVALID;
7188 
7189   if (value < SHRT_MIN)
7190     return E_FILE_FORMAT_INVALID;
7191 
7192   if (value > SHRT_MAX)
7193     return E_FILE_FORMAT_INVALID;
7194 
7195   m_timecode = static_cast<short>(value);
7196 
7197   pos += 2;
7198 
7199   if ((stop - pos) <= 0)
7200     return E_FILE_FORMAT_INVALID;
7201 
7202   status = pReader->Read(pos, 1, &m_flags);
7203 
7204   if (status)
7205     return E_FILE_FORMAT_INVALID;
7206 
7207   const int lacing = int(m_flags & 0x06) >> 1;
7208 
7209   ++pos;  // consume flags byte
7210 
7211   if (lacing == 0) {  // no lacing
7212     if (pos > stop)
7213       return E_FILE_FORMAT_INVALID;
7214 
7215     m_frame_count = 1;
7216     m_frames = new Frame[m_frame_count];
7217 
7218     Frame& f = m_frames[0];
7219     f.pos = pos;
7220 
7221     const long long frame_size = stop - pos;
7222 
7223     if (frame_size > LONG_MAX || frame_size <= 0)
7224       return E_FILE_FORMAT_INVALID;
7225 
7226     f.len = static_cast<long>(frame_size);
7227 
7228     return 0;  // success
7229   }
7230 
7231   if (pos >= stop)
7232     return E_FILE_FORMAT_INVALID;
7233 
7234   unsigned char biased_count;
7235 
7236   status = pReader->Read(pos, 1, &biased_count);
7237 
7238   if (status)
7239     return E_FILE_FORMAT_INVALID;
7240 
7241   ++pos;  // consume frame count
7242   assert(pos <= stop);
7243 
7244   m_frame_count = int(biased_count) + 1;
7245 
7246   m_frames = new Frame[m_frame_count];
7247   assert(m_frames);
7248 
7249   if (lacing == 1) {  // Xiph
7250     Frame* pf = m_frames;
7251     Frame* const pf_end = pf + m_frame_count;
7252 
7253     long size = 0;
7254     int frame_count = m_frame_count;
7255 
7256     while (frame_count > 1) {
7257       long frame_size = 0;
7258 
7259       for (;;) {
7260         unsigned char val;
7261 
7262         if (pos >= stop)
7263           return E_FILE_FORMAT_INVALID;
7264 
7265         status = pReader->Read(pos, 1, &val);
7266 
7267         if (status)
7268           return E_FILE_FORMAT_INVALID;
7269 
7270         ++pos;  // consume xiph size byte
7271 
7272         frame_size += val;
7273 
7274         if (val < 255)
7275           break;
7276       }
7277 
7278       Frame& f = *pf++;
7279       assert(pf < pf_end);
7280 
7281       f.pos = 0;  // patch later
7282 
7283       if (frame_size <= 0)
7284         return E_FILE_FORMAT_INVALID;
7285 
7286       f.len = frame_size;
7287       size += frame_size;  // contribution of this frame
7288 
7289       --frame_count;
7290     }
7291 
7292     assert(pf < pf_end);
7293     assert(pos <= stop);
7294 
7295     {
7296       Frame& f = *pf++;
7297 
7298       if (pf != pf_end)
7299         return E_FILE_FORMAT_INVALID;
7300 
7301       f.pos = 0;  // patch later
7302 
7303       const long long total_size = stop - pos;
7304 
7305       if (total_size < size)
7306         return E_FILE_FORMAT_INVALID;
7307 
7308       const long long frame_size = total_size - size;
7309 
7310       if (frame_size > LONG_MAX || frame_size <= 0)
7311         return E_FILE_FORMAT_INVALID;
7312 
7313       f.len = static_cast<long>(frame_size);
7314     }
7315 
7316     pf = m_frames;
7317     while (pf != pf_end) {
7318       Frame& f = *pf++;
7319       assert((pos + f.len) <= stop);
7320 
7321       f.pos = pos;
7322       pos += f.len;
7323     }
7324 
7325     assert(pos == stop);
7326   } else if (lacing == 2) {  // fixed-size lacing
7327     if (pos >= stop)
7328       return E_FILE_FORMAT_INVALID;
7329 
7330     const long long total_size = stop - pos;
7331 
7332     if ((total_size % m_frame_count) != 0)
7333       return E_FILE_FORMAT_INVALID;
7334 
7335     const long long frame_size = total_size / m_frame_count;
7336 
7337     if (frame_size > LONG_MAX || frame_size <= 0)
7338       return E_FILE_FORMAT_INVALID;
7339 
7340     Frame* pf = m_frames;
7341     Frame* const pf_end = pf + m_frame_count;
7342 
7343     while (pf != pf_end) {
7344       assert((pos + frame_size) <= stop);
7345 
7346       Frame& f = *pf++;
7347 
7348       f.pos = pos;
7349       f.len = static_cast<long>(frame_size);
7350 
7351       pos += frame_size;
7352     }
7353 
7354     assert(pos == stop);
7355   } else {
7356     assert(lacing == 3);  // EBML lacing
7357 
7358     if (pos >= stop)
7359       return E_FILE_FORMAT_INVALID;
7360 
7361     long size = 0;
7362     int frame_count = m_frame_count;
7363 
7364     long long frame_size = ReadUInt(pReader, pos, len);
7365 
7366     if (frame_size <= 0)
7367       return E_FILE_FORMAT_INVALID;
7368 
7369     if (frame_size > LONG_MAX)
7370       return E_FILE_FORMAT_INVALID;
7371 
7372     if ((pos + len) > stop)
7373       return E_FILE_FORMAT_INVALID;
7374 
7375     pos += len;  // consume length of size of first frame
7376 
7377     if ((pos + frame_size) > stop)
7378       return E_FILE_FORMAT_INVALID;
7379 
7380     Frame* pf = m_frames;
7381     Frame* const pf_end = pf + m_frame_count;
7382 
7383     {
7384       Frame& curr = *pf;
7385 
7386       curr.pos = 0;  // patch later
7387 
7388       curr.len = static_cast<long>(frame_size);
7389       size += curr.len;  // contribution of this frame
7390     }
7391 
7392     --frame_count;
7393 
7394     while (frame_count > 1) {
7395       if (pos >= stop)
7396         return E_FILE_FORMAT_INVALID;
7397 
7398       assert(pf < pf_end);
7399 
7400       const Frame& prev = *pf++;
7401       assert(prev.len == frame_size);
7402       if (prev.len != frame_size)
7403         return E_FILE_FORMAT_INVALID;
7404 
7405       assert(pf < pf_end);
7406 
7407       Frame& curr = *pf;
7408 
7409       curr.pos = 0;  // patch later
7410 
7411       const long long delta_size_ = ReadUInt(pReader, pos, len);
7412 
7413       if (delta_size_ < 0)
7414         return E_FILE_FORMAT_INVALID;
7415 
7416       if ((pos + len) > stop)
7417         return E_FILE_FORMAT_INVALID;
7418 
7419       pos += len;  // consume length of (delta) size
7420       assert(pos <= stop);
7421 
7422       const int exp = 7 * len - 1;
7423       const long long bias = (1LL << exp) - 1LL;
7424       const long long delta_size = delta_size_ - bias;
7425 
7426       frame_size += delta_size;
7427 
7428       if (frame_size <= 0)
7429         return E_FILE_FORMAT_INVALID;
7430 
7431       if (frame_size > LONG_MAX)
7432         return E_FILE_FORMAT_INVALID;
7433 
7434       curr.len = static_cast<long>(frame_size);
7435       size += curr.len;  // contribution of this frame
7436 
7437       --frame_count;
7438     }
7439 
7440     // parse last frame
7441     if (frame_count > 0) {
7442       assert(pos <= stop);
7443       assert(pf < pf_end);
7444 
7445       const Frame& prev = *pf++;
7446       assert(prev.len == frame_size);
7447       if (prev.len != frame_size)
7448         return E_FILE_FORMAT_INVALID;
7449 
7450       assert(pf < pf_end);
7451 
7452       Frame& curr = *pf++;
7453       assert(pf == pf_end);
7454 
7455       curr.pos = 0;  // patch later
7456 
7457       const long long total_size = stop - pos;
7458 
7459       if (total_size < size)
7460         return E_FILE_FORMAT_INVALID;
7461 
7462       frame_size = total_size - size;
7463 
7464       if (frame_size > LONG_MAX || frame_size <= 0)
7465         return E_FILE_FORMAT_INVALID;
7466 
7467       curr.len = static_cast<long>(frame_size);
7468     }
7469 
7470     pf = m_frames;
7471     while (pf != pf_end) {
7472       Frame& f = *pf++;
7473       assert((pos + f.len) <= stop);
7474 
7475       f.pos = pos;
7476       pos += f.len;
7477     }
7478 
7479     if (pos != stop)
7480       return E_FILE_FORMAT_INVALID;
7481   }
7482 
7483   return 0;  // success
7484 }
7485 
GetTimeCode(const Cluster * pCluster) const7486 long long Block::GetTimeCode(const Cluster* pCluster) const {
7487   if (pCluster == 0)
7488     return m_timecode;
7489 
7490   const long long tc0 = pCluster->GetTimeCode();
7491   assert(tc0 >= 0);
7492 
7493   const long long tc = tc0 + m_timecode;
7494 
7495   return tc;  // unscaled timecode units
7496 }
7497 
GetTime(const Cluster * pCluster) const7498 long long Block::GetTime(const Cluster* pCluster) const {
7499   assert(pCluster);
7500 
7501   const long long tc = GetTimeCode(pCluster);
7502 
7503   const Segment* const pSegment = pCluster->m_pSegment;
7504   const SegmentInfo* const pInfo = pSegment->GetInfo();
7505   assert(pInfo);
7506 
7507   const long long scale = pInfo->GetTimeCodeScale();
7508   assert(scale >= 1);
7509 
7510   const long long ns = tc * scale;
7511 
7512   return ns;
7513 }
7514 
GetTrackNumber() const7515 long long Block::GetTrackNumber() const { return m_track; }
7516 
IsKey() const7517 bool Block::IsKey() const {
7518   return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
7519 }
7520 
SetKey(bool bKey)7521 void Block::SetKey(bool bKey) {
7522   if (bKey)
7523     m_flags |= static_cast<unsigned char>(1 << 7);
7524   else
7525     m_flags &= 0x7F;
7526 }
7527 
IsInvisible() const7528 bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
7529 
GetLacing() const7530 Block::Lacing Block::GetLacing() const {
7531   const int value = int(m_flags & 0x06) >> 1;
7532   return static_cast<Lacing>(value);
7533 }
7534 
GetFrameCount() const7535 int Block::GetFrameCount() const { return m_frame_count; }
7536 
GetFrame(int idx) const7537 const Block::Frame& Block::GetFrame(int idx) const {
7538   assert(idx >= 0);
7539   assert(idx < m_frame_count);
7540 
7541   const Frame& f = m_frames[idx];
7542   assert(f.pos > 0);
7543   assert(f.len > 0);
7544 
7545   return f;
7546 }
7547 
Read(IMkvReader * pReader,unsigned char * buf) const7548 long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
7549   assert(pReader);
7550   assert(buf);
7551 
7552   const long status = pReader->Read(pos, len, buf);
7553   return status;
7554 }
7555 
GetDiscardPadding() const7556 long long Block::GetDiscardPadding() const { return m_discard_padding; }
7557 
7558 }  // end namespace mkvparser
7559