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