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