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