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    //TODO: here and elsewhere, it's probably not correct to search
2644    //for the cue point with this time, and then search for a matching
2645    //track.  In principle, the matching track could be on some earlier
2646    //cue point, and with our current algorithm, we'd miss it.  To make
2647    //this bullet-proof, we'd need to create a secondary structure,
2648    //with a list of cue points that apply to a track, and then search
2649    //that track-based structure for a matching cue point.
2650
2651    pTP = pCP->Find(pTrack);
2652    return (pTP != NULL);
2653}
2654
2655
2656#if 0
2657bool Cues::FindNext(
2658    long long time_ns,
2659    const Track* pTrack,
2660    const CuePoint*& pCP,
2661    const CuePoint::TrackPosition*& pTP) const
2662{
2663    pCP = 0;
2664    pTP = 0;
2665
2666    if (m_count == 0)
2667        return false;
2668
2669    assert(m_cue_points);
2670
2671    const CuePoint* const* const ii = m_cue_points;
2672    const CuePoint* const* i = ii;
2673
2674    const CuePoint* const* const jj = ii + m_count;
2675    const CuePoint* const* j = jj;
2676
2677    while (i < j)
2678    {
2679        //INVARIANT:
2680        //[ii, i) <= time_ns
2681        //[i, j)  ?
2682        //[j, jj) > time_ns
2683
2684        const CuePoint* const* const k = i + (j - i) / 2;
2685        assert(k < jj);
2686
2687        pCP = *k;
2688        assert(pCP);
2689
2690        const long long t = pCP->GetTime(m_pSegment);
2691
2692        if (t <= time_ns)
2693            i = k + 1;
2694        else
2695            j = k;
2696
2697        assert(i <= j);
2698    }
2699
2700    assert(i == j);
2701    assert(i <= jj);
2702
2703    if (i >= jj)  //time_ns is greater than max cue point
2704        return false;
2705
2706    pCP = *i;
2707    assert(pCP);
2708    assert(pCP->GetTime(m_pSegment) > time_ns);
2709
2710    pTP = pCP->Find(pTrack);
2711    return (pTP != NULL);
2712}
2713#endif
2714
2715
2716const CuePoint* Cues::GetFirst() const
2717{
2718    if (m_cue_points == NULL)
2719        return NULL;
2720
2721    if (m_count == 0)
2722        return NULL;
2723
2724#if 0
2725    LoadCuePoint();  //init cues
2726
2727    const size_t count = m_count + m_preload_count;
2728
2729    if (count == 0)  //weird
2730        return NULL;
2731#endif
2732
2733    CuePoint* const* const pp = m_cue_points;
2734    assert(pp);
2735
2736    CuePoint* const pCP = pp[0];
2737    assert(pCP);
2738    assert(pCP->GetTimeCode() >= 0);
2739
2740    return pCP;
2741}
2742
2743
2744const CuePoint* Cues::GetLast() const
2745{
2746    if (m_cue_points == NULL)
2747        return NULL;
2748
2749    if (m_count <= 0)
2750        return NULL;
2751
2752#if 0
2753    LoadCuePoint();  //init cues
2754
2755    const size_t count = m_count + m_preload_count;
2756
2757    if (count == 0)  //weird
2758        return NULL;
2759
2760    const size_t index = count - 1;
2761
2762    CuePoint* const* const pp = m_cue_points;
2763    assert(pp);
2764
2765    CuePoint* const pCP = pp[index];
2766    assert(pCP);
2767
2768    pCP->Load(m_pSegment->m_pReader);
2769    assert(pCP->GetTimeCode() >= 0);
2770#else
2771    const long index = m_count - 1;
2772
2773    CuePoint* const* const pp = m_cue_points;
2774    assert(pp);
2775
2776    CuePoint* const pCP = pp[index];
2777    assert(pCP);
2778    assert(pCP->GetTimeCode() >= 0);
2779#endif
2780
2781    return pCP;
2782}
2783
2784
2785const CuePoint* Cues::GetNext(const CuePoint* pCurr) const
2786{
2787    if (pCurr == NULL)
2788        return NULL;
2789
2790    assert(pCurr->GetTimeCode() >= 0);
2791    assert(m_cue_points);
2792    assert(m_count >= 1);
2793
2794#if 0
2795    const size_t count = m_count + m_preload_count;
2796
2797    size_t index = pCurr->m_index;
2798    assert(index < count);
2799
2800    CuePoint* const* const pp = m_cue_points;
2801    assert(pp);
2802    assert(pp[index] == pCurr);
2803
2804    ++index;
2805
2806    if (index >= count)
2807        return NULL;
2808
2809    CuePoint* const pNext = pp[index];
2810    assert(pNext);
2811
2812    pNext->Load(m_pSegment->m_pReader);
2813#else
2814    long index = pCurr->m_index;
2815    assert(index < m_count);
2816
2817    CuePoint* const* const pp = m_cue_points;
2818    assert(pp);
2819    assert(pp[index] == pCurr);
2820
2821    ++index;
2822
2823    if (index >= m_count)
2824        return NULL;
2825
2826    CuePoint* const pNext = pp[index];
2827    assert(pNext);
2828    assert(pNext->GetTimeCode() >= 0);
2829#endif
2830
2831    return pNext;
2832}
2833
2834
2835const BlockEntry* Cues::GetBlock(
2836    const CuePoint* pCP,
2837    const CuePoint::TrackPosition* pTP) const
2838{
2839    if (pCP == NULL)
2840        return NULL;
2841
2842    if (pTP == NULL)
2843        return NULL;
2844
2845    return m_pSegment->GetBlock(*pCP, *pTP);
2846}
2847
2848
2849const BlockEntry* Segment::GetBlock(
2850    const CuePoint& cp,
2851    const CuePoint::TrackPosition& tp)
2852{
2853    Cluster** const ii = m_clusters;
2854    Cluster** i = ii;
2855
2856    const long count = m_clusterCount + m_clusterPreloadCount;
2857
2858    Cluster** const jj = ii + count;
2859    Cluster** j = jj;
2860
2861    while (i < j)
2862    {
2863        //INVARIANT:
2864        //[ii, i) < pTP->m_pos
2865        //[i, j) ?
2866        //[j, jj)  > pTP->m_pos
2867
2868        Cluster** const k = i + (j - i) / 2;
2869        assert(k < jj);
2870
2871        Cluster* const pCluster = *k;
2872        assert(pCluster);
2873
2874        //const long long pos_ = pCluster->m_pos;
2875        //assert(pos_);
2876        //const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2877
2878        const long long pos = pCluster->GetPosition();
2879        assert(pos >= 0);
2880
2881        if (pos < tp.m_pos)
2882            i = k + 1;
2883        else if (pos > tp.m_pos)
2884            j = k;
2885        else
2886            return pCluster->GetEntry(cp, tp);
2887    }
2888
2889    assert(i == j);
2890    //assert(Cluster::HasBlockEntries(this, tp.m_pos));
2891
2892    Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1);
2893    assert(pCluster);
2894
2895    const ptrdiff_t idx = i - m_clusters;
2896
2897    PreloadCluster(pCluster, idx);
2898    assert(m_clusters);
2899    assert(m_clusterPreloadCount > 0);
2900    assert(m_clusters[idx] == pCluster);
2901
2902    return pCluster->GetEntry(cp, tp);
2903}
2904
2905
2906const Cluster* Segment::FindOrPreloadCluster(long long requested_pos)
2907{
2908    if (requested_pos < 0)
2909        return 0;
2910
2911    Cluster** const ii = m_clusters;
2912    Cluster** i = ii;
2913
2914    const long count = m_clusterCount + m_clusterPreloadCount;
2915
2916    Cluster** const jj = ii + count;
2917    Cluster** j = jj;
2918
2919    while (i < j)
2920    {
2921        //INVARIANT:
2922        //[ii, i) < pTP->m_pos
2923        //[i, j) ?
2924        //[j, jj)  > pTP->m_pos
2925
2926        Cluster** const k = i + (j - i) / 2;
2927        assert(k < jj);
2928
2929        Cluster* const pCluster = *k;
2930        assert(pCluster);
2931
2932        //const long long pos_ = pCluster->m_pos;
2933        //assert(pos_);
2934        //const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2935
2936        const long long pos = pCluster->GetPosition();
2937        assert(pos >= 0);
2938
2939        if (pos < requested_pos)
2940            i = k + 1;
2941        else if (pos > requested_pos)
2942            j = k;
2943        else
2944            return pCluster;
2945    }
2946
2947    assert(i == j);
2948    //assert(Cluster::HasBlockEntries(this, tp.m_pos));
2949
2950    Cluster* const pCluster = Cluster::Create(
2951                                this,
2952                                -1,
2953                                requested_pos);
2954                                //-1);
2955    assert(pCluster);
2956
2957    const ptrdiff_t idx = i - m_clusters;
2958
2959    PreloadCluster(pCluster, idx);
2960    assert(m_clusters);
2961    assert(m_clusterPreloadCount > 0);
2962    assert(m_clusters[idx] == pCluster);
2963
2964    return pCluster;
2965}
2966
2967
2968CuePoint::CuePoint(long idx, long long pos) :
2969    m_element_start(0),
2970    m_element_size(0),
2971    m_index(idx),
2972    m_timecode(-1 * pos),
2973    m_track_positions(NULL),
2974    m_track_positions_count(0)
2975{
2976    assert(pos > 0);
2977}
2978
2979
2980CuePoint::~CuePoint()
2981{
2982    delete[] m_track_positions;
2983}
2984
2985
2986void CuePoint::Load(IMkvReader* pReader)
2987{
2988    //odbgstream os;
2989    //os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
2990
2991    if (m_timecode >= 0)  //already loaded
2992        return;
2993
2994    assert(m_track_positions == NULL);
2995    assert(m_track_positions_count == 0);
2996
2997    long long pos_ = -m_timecode;
2998    const long long element_start = pos_;
2999
3000    long long stop;
3001
3002    {
3003        long len;
3004
3005        const long long id = ReadUInt(pReader, pos_, len);
3006        assert(id == 0x3B);  //CuePoint ID
3007        //assert((pos + len) <= stop);
3008
3009        pos_ += len;  //consume ID
3010
3011        const long long size = ReadUInt(pReader, pos_, len);
3012        assert(size >= 0);
3013        //assert((pos + len) <= stop);
3014
3015        pos_ += len;  //consume Size field
3016        //assert((pos + size) <= stop);
3017
3018        //pos_ now points to start of payload
3019
3020        stop = pos_ + size;
3021    }
3022
3023    const long long element_size = stop - element_start;
3024
3025    long long pos = pos_;
3026
3027    //First count number of track positions
3028
3029    while (pos < stop)
3030    {
3031        long len;
3032
3033        const long long id = ReadUInt(pReader, pos, len);
3034        assert(id >= 0);  //TODO
3035        assert((pos + len) <= stop);
3036
3037        pos += len;  //consume ID
3038
3039        const long long size = ReadUInt(pReader, pos, len);
3040        assert(size >= 0);
3041        assert((pos + len) <= stop);
3042
3043        pos += len;  //consume Size field
3044        assert((pos + size) <= stop);
3045
3046        if (id == 0x33)  //CueTime ID
3047            m_timecode = UnserializeUInt(pReader, pos, size);
3048
3049        else if (id == 0x37) //CueTrackPosition(s) ID
3050            ++m_track_positions_count;
3051
3052        pos += size;  //consume payload
3053        assert(pos <= stop);
3054    }
3055
3056    assert(m_timecode >= 0);
3057    assert(m_track_positions_count > 0);
3058
3059    //os << "CuePoint::Load(cont'd): idpos=" << idpos
3060    //   << " timecode=" << m_timecode
3061    //   << endl;
3062
3063    m_track_positions = new TrackPosition[m_track_positions_count];
3064
3065    //Now parse track positions
3066
3067    TrackPosition* p = m_track_positions;
3068    pos = pos_;
3069
3070    while (pos < stop)
3071    {
3072        long len;
3073
3074        const long long id = ReadUInt(pReader, pos, len);
3075        assert(id >= 0);  //TODO
3076        assert((pos + len) <= stop);
3077
3078        pos += len;  //consume ID
3079
3080        const long long size = ReadUInt(pReader, pos, len);
3081        assert(size >= 0);
3082        assert((pos + len) <= stop);
3083
3084        pos += len;  //consume Size field
3085        assert((pos + size) <= stop);
3086
3087        if (id == 0x37) //CueTrackPosition(s) ID
3088        {
3089            TrackPosition& tp = *p++;
3090            tp.Parse(pReader, pos, size);
3091        }
3092
3093        pos += size;  //consume payload
3094        assert(pos <= stop);
3095    }
3096
3097    assert(size_t(p - m_track_positions) == m_track_positions_count);
3098
3099    m_element_start = element_start;
3100    m_element_size = element_size;
3101}
3102
3103
3104
3105void CuePoint::TrackPosition::Parse(
3106    IMkvReader* pReader,
3107    long long start_,
3108    long long size_)
3109{
3110    const long long stop = start_ + size_;
3111    long long pos = start_;
3112
3113    m_track = -1;
3114    m_pos = -1;
3115    m_block = 1;  //default
3116
3117    while (pos < stop)
3118    {
3119        long len;
3120
3121        const long long id = ReadUInt(pReader, pos, len);
3122        assert(id >= 0);  //TODO
3123        assert((pos + len) <= stop);
3124
3125        pos += len;  //consume ID
3126
3127        const long long size = ReadUInt(pReader, pos, len);
3128        assert(size >= 0);
3129        assert((pos + len) <= stop);
3130
3131        pos += len;  //consume Size field
3132        assert((pos + size) <= stop);
3133
3134        if (id == 0x77)  //CueTrack ID
3135            m_track = UnserializeUInt(pReader, pos, size);
3136
3137        else if (id == 0x71)  //CueClusterPos ID
3138            m_pos = UnserializeUInt(pReader, pos, size);
3139
3140        else if (id == 0x1378)  //CueBlockNumber
3141            m_block = UnserializeUInt(pReader, pos, size);
3142
3143        pos += size;  //consume payload
3144        assert(pos <= stop);
3145    }
3146
3147    assert(m_pos >= 0);
3148    assert(m_track > 0);
3149    //assert(m_block > 0);
3150}
3151
3152
3153const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const
3154{
3155    assert(pTrack);
3156
3157    const long long n = pTrack->GetNumber();
3158
3159    const TrackPosition* i = m_track_positions;
3160    const TrackPosition* const j = i + m_track_positions_count;
3161
3162    while (i != j)
3163    {
3164        const TrackPosition& p = *i++;
3165
3166        if (p.m_track == n)
3167            return &p;
3168    }
3169
3170    return NULL;  //no matching track number found
3171}
3172
3173
3174long long CuePoint::GetTimeCode() const
3175{
3176    return m_timecode;
3177}
3178
3179long long CuePoint::GetTime(const Segment* pSegment) const
3180{
3181    assert(pSegment);
3182    assert(m_timecode >= 0);
3183
3184    const SegmentInfo* const pInfo = pSegment->GetInfo();
3185    assert(pInfo);
3186
3187    const long long scale = pInfo->GetTimeCodeScale();
3188    assert(scale >= 1);
3189
3190    const long long time = scale * m_timecode;
3191
3192    return time;
3193}
3194
3195
3196#if 0
3197long long Segment::Unparsed() const
3198{
3199    if (m_size < 0)
3200        return LLONG_MAX;
3201
3202    const long long stop = m_start + m_size;
3203
3204    const long long result = stop - m_pos;
3205    assert(result >= 0);
3206
3207    return result;
3208}
3209#else
3210bool Segment::DoneParsing() const
3211{
3212    if (m_size < 0)
3213    {
3214        long long total, avail;
3215
3216        const int status = m_pReader->Length(&total, &avail);
3217
3218        if (status < 0)  //error
3219            return true;  //must assume done
3220
3221        if (total < 0)
3222            return false;  //assume live stream
3223
3224        return (m_pos >= total);
3225    }
3226
3227    const long long stop = m_start + m_size;
3228
3229    return (m_pos >= stop);
3230}
3231#endif
3232
3233
3234const Cluster* Segment::GetFirst() const
3235{
3236    if ((m_clusters == NULL) || (m_clusterCount <= 0))
3237       return &m_eos;
3238
3239    Cluster* const pCluster = m_clusters[0];
3240    assert(pCluster);
3241
3242    return pCluster;
3243}
3244
3245
3246const Cluster* Segment::GetLast() const
3247{
3248    if ((m_clusters == NULL) || (m_clusterCount <= 0))
3249        return &m_eos;
3250
3251    const long idx = m_clusterCount - 1;
3252
3253    Cluster* const pCluster = m_clusters[idx];
3254    assert(pCluster);
3255
3256    return pCluster;
3257}
3258
3259
3260unsigned long Segment::GetCount() const
3261{
3262    return m_clusterCount;
3263}
3264
3265
3266const Cluster* Segment::GetNext(const Cluster* pCurr)
3267{
3268    assert(pCurr);
3269    assert(pCurr != &m_eos);
3270    assert(m_clusters);
3271
3272    long idx =  pCurr->m_index;
3273
3274    if (idx >= 0)
3275    {
3276        assert(m_clusterCount > 0);
3277        assert(idx < m_clusterCount);
3278        assert(pCurr == m_clusters[idx]);
3279
3280        ++idx;
3281
3282        if (idx >= m_clusterCount)
3283            return &m_eos;  //caller will LoadCluster as desired
3284
3285        Cluster* const pNext = m_clusters[idx];
3286        assert(pNext);
3287        assert(pNext->m_index >= 0);
3288        assert(pNext->m_index == idx);
3289
3290        return pNext;
3291    }
3292
3293    assert(m_clusterPreloadCount > 0);
3294
3295    //const long long off_ = pCurr->m_pos;
3296    //const long long off = off_ * ((off_ < 0) ? -1 : 1);
3297    //long long pos = m_start + off;
3298
3299    long long pos = pCurr->m_element_start;
3300
3301    assert(m_size >= 0);  //TODO
3302    const long long stop = m_start + m_size;  //end of segment
3303
3304    {
3305        long len;
3306
3307        long long result = GetUIntLength(m_pReader, pos, len);
3308        assert(result == 0);  //TODO
3309        assert((pos + len) <= stop);  //TODO
3310
3311        const long long id = ReadUInt(m_pReader, pos, len);
3312        assert(id == 0x0F43B675);  //Cluster ID   //TODO
3313
3314        pos += len;  //consume ID
3315
3316        //Read Size
3317        result = GetUIntLength(m_pReader, pos, len);
3318        assert(result == 0);  //TODO
3319        assert((pos + len) <= stop);  //TODO
3320
3321        const long long size = ReadUInt(m_pReader, pos, len);
3322        assert(size > 0);  //TODO
3323        //assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
3324
3325        pos += len;  //consume length of size of element
3326        assert((pos + size) <= stop);  //TODO
3327
3328        //Pos now points to start of payload
3329
3330        pos += size;  //consume payload
3331    }
3332
3333    long long off_next = 0;
3334    //long long element_start_next = 0;
3335    long long element_size_next = 0;
3336
3337    while (pos < stop)
3338    {
3339        long len;
3340
3341        long long result = GetUIntLength(m_pReader, pos, len);
3342        assert(result == 0);  //TODO
3343        assert((pos + len) <= stop);  //TODO
3344
3345        const long long idpos = pos;  //pos of next (potential) cluster
3346
3347        const long long id = ReadUInt(m_pReader, idpos, len);
3348        assert(id > 0);  //TODO
3349
3350        pos += len;  //consume ID
3351
3352        //Read Size
3353        result = GetUIntLength(m_pReader, pos, len);
3354        assert(result == 0);  //TODO
3355        assert((pos + len) <= stop);  //TODO
3356
3357        const long long size = ReadUInt(m_pReader, pos, len);
3358        assert(size >= 0);  //TODO
3359
3360        pos += len;  //consume length of size of element
3361        assert((pos + size) <= stop);  //TODO
3362
3363        const long long element_size = size + pos - idpos;
3364
3365        //Pos now points to start of payload
3366
3367        if (size == 0)  //weird
3368            continue;
3369
3370        if (id == 0x0F43B675)  //Cluster ID
3371        {
3372            const long long off_next_ = idpos - m_start;
3373
3374            long long pos_;
3375            long len_;
3376
3377            const long status = Cluster::HasBlockEntries(
3378                                    this,
3379                                    off_next_,
3380                                    pos_,
3381                                    len_);
3382
3383            assert(status >= 0);
3384
3385            if (status > 0)
3386            {
3387                off_next = off_next_;
3388                //element_start_next = idpos;
3389                element_size_next = element_size;
3390                break;
3391            }
3392        }
3393
3394        pos += size;  //consume payload
3395    }
3396
3397    if (off_next <= 0)
3398        return 0;
3399
3400    Cluster** const ii = m_clusters + m_clusterCount;
3401    Cluster** i = ii;
3402
3403    Cluster** const jj = ii + m_clusterPreloadCount;
3404    Cluster** j = jj;
3405
3406    while (i < j)
3407    {
3408        //INVARIANT:
3409        //[0, i) < pos_next
3410        //[i, j) ?
3411        //[j, jj)  > pos_next
3412
3413        Cluster** const k = i + (j - i) / 2;
3414        assert(k < jj);
3415
3416        Cluster* const pNext = *k;
3417        assert(pNext);
3418        assert(pNext->m_index < 0);
3419
3420        //const long long pos_ = pNext->m_pos;
3421        //assert(pos_);
3422        //pos = pos_ * ((pos_ < 0) ? -1 : 1);
3423
3424        pos = pNext->GetPosition();
3425
3426        if (pos < off_next)
3427            i = k + 1;
3428        else if (pos > off_next)
3429            j = k;
3430        else
3431            return pNext;
3432    }
3433
3434    assert(i == j);
3435
3436    Cluster* const pNext = Cluster::Create(this,
3437                                          -1,
3438                                          off_next);
3439                                          //element_size_next);
3440    assert(pNext);
3441
3442    const ptrdiff_t idx_next = i - m_clusters;  //insertion position
3443
3444    PreloadCluster(pNext, idx_next);
3445    assert(m_clusters);
3446    assert(idx_next < m_clusterSize);
3447    assert(m_clusters[idx_next] == pNext);
3448
3449    return pNext;
3450}
3451
3452
3453long Segment::ParseNext(
3454    const Cluster* pCurr,
3455    const Cluster*& pResult,
3456    long long& pos,
3457    long& len)
3458{
3459    assert(pCurr);
3460    assert(!pCurr->EOS());
3461    assert(m_clusters);
3462
3463    pResult = 0;
3464
3465    if (pCurr->m_index >= 0)  //loaded (not merely preloaded)
3466    {
3467        assert(m_clusters[pCurr->m_index] == pCurr);
3468
3469        const long next_idx = pCurr->m_index + 1;
3470
3471        if (next_idx < m_clusterCount)
3472        {
3473            pResult = m_clusters[next_idx];
3474            return 0;  //success
3475        }
3476
3477        //curr cluster is last among loaded
3478
3479        const long result = LoadCluster(pos, len);
3480
3481        if (result < 0)  //error or underflow
3482            return result;
3483
3484        if (result > 0)  //no more clusters
3485        {
3486            //pResult = &m_eos;
3487            return 1;
3488        }
3489
3490        pResult = GetLast();
3491        return 0;  //success
3492    }
3493
3494    assert(m_pos > 0);
3495
3496    long long total, avail;
3497
3498    long status = m_pReader->Length(&total, &avail);
3499
3500    if (status < 0)  //error
3501        return status;
3502
3503    assert((total < 0) || (avail <= total));
3504
3505    const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
3506
3507    //interrogate curr cluster
3508
3509    pos = pCurr->m_element_start;
3510
3511    if (pCurr->m_element_size >= 0)
3512        pos += pCurr->m_element_size;
3513    else
3514    {
3515        if ((pos + 1) > avail)
3516        {
3517            len = 1;
3518            return E_BUFFER_NOT_FULL;
3519        }
3520
3521        long long result = GetUIntLength(m_pReader, pos, len);
3522
3523        if (result < 0)  //error
3524            return static_cast<long>(result);
3525
3526        if (result > 0)  //weird
3527            return E_BUFFER_NOT_FULL;
3528
3529        if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3530            return E_FILE_FORMAT_INVALID;
3531
3532        if ((pos + len) > avail)
3533            return E_BUFFER_NOT_FULL;
3534
3535        const long long id = ReadUInt(m_pReader, pos, len);
3536
3537        if (id != 0x0F43B675)  //weird: not Cluster ID
3538            return -1;
3539
3540        pos += len;  //consume ID
3541
3542        //Read Size
3543
3544        if ((pos + 1) > avail)
3545        {
3546            len = 1;
3547            return E_BUFFER_NOT_FULL;
3548        }
3549
3550        result = GetUIntLength(m_pReader, pos, len);
3551
3552        if (result < 0)  //error
3553            return static_cast<long>(result);
3554
3555        if (result > 0)  //weird
3556            return E_BUFFER_NOT_FULL;
3557
3558        if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3559            return E_FILE_FORMAT_INVALID;
3560
3561        if ((pos + len) > avail)
3562            return E_BUFFER_NOT_FULL;
3563
3564        const long long size = ReadUInt(m_pReader, pos, len);
3565
3566        if (size < 0) //error
3567            return static_cast<long>(size);
3568
3569        pos += len;  //consume size field
3570
3571        const long long unknown_size = (1LL << (7 * len)) - 1;
3572
3573        if (size == unknown_size)          //TODO: should never happen
3574            return E_FILE_FORMAT_INVALID;  //TODO: resolve this
3575
3576        //assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
3577
3578        if ((segment_stop >= 0) && ((pos + size) > segment_stop))
3579            return E_FILE_FORMAT_INVALID;
3580
3581        //Pos now points to start of payload
3582
3583        pos += size;  //consume payload (that is, the current cluster)
3584        assert((segment_stop < 0) || (pos <= segment_stop));
3585
3586        //By consuming the payload, we are assuming that the curr
3587        //cluster isn't interesting.  That is, we don't bother checking
3588        //whether the payload of the curr cluster is less than what
3589        //happens to be available (obtained via IMkvReader::Length).
3590        //Presumably the caller has already dispensed with the current
3591        //cluster, and really does want the next cluster.
3592    }
3593
3594    //pos now points to just beyond the last fully-loaded cluster
3595
3596    for (;;)
3597    {
3598        const long status = DoParseNext(pResult, pos, len);
3599
3600        if (status <= 1)
3601            return status;
3602    }
3603}
3604
3605
3606long Segment::DoParseNext(
3607    const Cluster*& pResult,
3608    long long& pos,
3609    long& len)
3610{
3611    long long total, avail;
3612
3613    long status = m_pReader->Length(&total, &avail);
3614
3615    if (status < 0)  //error
3616        return status;
3617
3618    assert((total < 0) || (avail <= total));
3619
3620    const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
3621
3622    //Parse next cluster.  This is strictly a parsing activity.
3623    //Creation of a new cluster object happens later, after the
3624    //parsing is done.
3625
3626    long long off_next = 0;
3627    long long cluster_size = -1;
3628
3629    for (;;)
3630    {
3631        if ((total >= 0) && (pos >= total))
3632            return 1;  //EOF
3633
3634        if ((segment_stop >= 0) && (pos >= segment_stop))
3635            return 1;  //EOF
3636
3637        if ((pos + 1) > avail)
3638        {
3639            len = 1;
3640            return E_BUFFER_NOT_FULL;
3641        }
3642
3643        long long result = GetUIntLength(m_pReader, pos, len);
3644
3645        if (result < 0)  //error
3646            return static_cast<long>(result);
3647
3648        if (result > 0)  //weird
3649            return E_BUFFER_NOT_FULL;
3650
3651        if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3652            return E_FILE_FORMAT_INVALID;
3653
3654        if ((pos + len) > avail)
3655            return E_BUFFER_NOT_FULL;
3656
3657        const long long idpos = pos;             //absolute
3658        const long long idoff = pos - m_start;   //relative
3659
3660        const long long id = ReadUInt(m_pReader, idpos, len);  //absolute
3661
3662        if (id < 0)  //error
3663            return static_cast<long>(id);
3664
3665        if (id == 0)  //weird
3666            return -1;  //generic error
3667
3668        pos += len;  //consume ID
3669
3670        //Read Size
3671
3672        if ((pos + 1) > avail)
3673        {
3674            len = 1;
3675            return E_BUFFER_NOT_FULL;
3676        }
3677
3678        result = GetUIntLength(m_pReader, pos, len);
3679
3680        if (result < 0)  //error
3681            return static_cast<long>(result);
3682
3683        if (result > 0)  //weird
3684            return E_BUFFER_NOT_FULL;
3685
3686        if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3687            return E_FILE_FORMAT_INVALID;
3688
3689        if ((pos + len) > avail)
3690            return E_BUFFER_NOT_FULL;
3691
3692        const long long size = ReadUInt(m_pReader, pos, len);
3693
3694        if (size < 0)  //error
3695            return static_cast<long>(size);
3696
3697        pos += len;  //consume length of size of element
3698
3699        //Pos now points to start of payload
3700
3701        if (size == 0)  //weird
3702            continue;
3703
3704        const long long unknown_size = (1LL << (7 * len)) - 1;
3705
3706        if ((segment_stop >= 0) &&
3707            (size != unknown_size) &&
3708            ((pos + size) > segment_stop))
3709        {
3710            return E_FILE_FORMAT_INVALID;
3711        }
3712
3713        if (id == 0x0C53BB6B)  //Cues ID
3714        {
3715            if (size == unknown_size)
3716                return E_FILE_FORMAT_INVALID;
3717
3718            const long long element_stop = pos + size;
3719
3720            if ((segment_stop >= 0) && (element_stop > segment_stop))
3721                return E_FILE_FORMAT_INVALID;
3722
3723            const long long element_start = idpos;
3724            const long long element_size = element_stop - element_start;
3725
3726            if (m_pCues == NULL)
3727            {
3728                m_pCues = new Cues(this,
3729                                    pos,
3730                                    size,
3731                                    element_start,
3732                                    element_size);
3733                assert(m_pCues);  //TODO
3734            }
3735
3736            pos += size;  //consume payload
3737            assert((segment_stop < 0) || (pos <= segment_stop));
3738
3739            continue;
3740        }
3741
3742        if (id != 0x0F43B675)  //not a Cluster ID
3743        {
3744            if (size == unknown_size)
3745                return E_FILE_FORMAT_INVALID;
3746
3747            pos += size;  //consume payload
3748            assert((segment_stop < 0) || (pos <= segment_stop));
3749
3750            continue;
3751        }
3752
3753#if 0 //this is commented-out to support incremental cluster parsing
3754        len = static_cast<long>(size);
3755
3756        if (element_stop > avail)
3757            return E_BUFFER_NOT_FULL;
3758#endif
3759
3760        //We have a cluster.
3761
3762        off_next = idoff;
3763
3764        if (size != unknown_size)
3765            cluster_size = size;
3766
3767        break;
3768    }
3769
3770    assert(off_next > 0);  //have cluster
3771
3772    //We have parsed the next cluster.
3773    //We have not created a cluster object yet.  What we need
3774    //to do now is determine whether it has already be preloaded
3775    //(in which case, an object for this cluster has already been
3776    //created), and if not, create a new cluster object.
3777
3778    Cluster** const ii = m_clusters + m_clusterCount;
3779    Cluster** i = ii;
3780
3781    Cluster** const jj = ii + m_clusterPreloadCount;
3782    Cluster** j = jj;
3783
3784    while (i < j)
3785    {
3786        //INVARIANT:
3787        //[0, i) < pos_next
3788        //[i, j) ?
3789        //[j, jj)  > pos_next
3790
3791        Cluster** const k = i + (j - i) / 2;
3792        assert(k < jj);
3793
3794        const Cluster* const pNext = *k;
3795        assert(pNext);
3796        assert(pNext->m_index < 0);
3797
3798        pos = pNext->GetPosition();
3799        assert(pos >= 0);
3800
3801        if (pos < off_next)
3802            i = k + 1;
3803        else if (pos > off_next)
3804            j = k;
3805        else
3806        {
3807            pResult = pNext;
3808            return 0;  //success
3809        }
3810    }
3811
3812    assert(i == j);
3813
3814    long long pos_;
3815    long len_;
3816
3817    status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
3818
3819    if (status < 0)  //error or underflow
3820    {
3821        pos = pos_;
3822        len = len_;
3823
3824        return status;
3825    }
3826
3827    if (status > 0)  //means "found at least one block entry"
3828    {
3829        Cluster* const pNext = Cluster::Create(this,
3830                                                -1,   //preloaded
3831                                                off_next);
3832                                                //element_size);
3833        assert(pNext);
3834
3835        const ptrdiff_t idx_next = i - m_clusters;  //insertion position
3836
3837        PreloadCluster(pNext, idx_next);
3838        assert(m_clusters);
3839        assert(idx_next < m_clusterSize);
3840        assert(m_clusters[idx_next] == pNext);
3841
3842        pResult = pNext;
3843        return 0;  //success
3844    }
3845
3846    //status == 0 means "no block entries found"
3847
3848    if (cluster_size < 0)  //unknown size
3849    {
3850        const long long payload_pos = pos;  //absolute pos of cluster payload
3851
3852        for (;;)  //determine cluster size
3853        {
3854            if ((total >= 0) && (pos >= total))
3855                break;
3856
3857            if ((segment_stop >= 0) && (pos >= segment_stop))
3858                break;  //no more clusters
3859
3860            //Read ID
3861
3862            if ((pos + 1) > avail)
3863            {
3864                len = 1;
3865                return E_BUFFER_NOT_FULL;
3866            }
3867
3868            long long result = GetUIntLength(m_pReader, pos, len);
3869
3870            if (result < 0)  //error
3871                return static_cast<long>(result);
3872
3873            if (result > 0)  //weird
3874                return E_BUFFER_NOT_FULL;
3875
3876            if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3877                return E_FILE_FORMAT_INVALID;
3878
3879            if ((pos + len) > avail)
3880                return E_BUFFER_NOT_FULL;
3881
3882            const long long idpos = pos;
3883            const long long id = ReadUInt(m_pReader, idpos, len);
3884
3885            if (id < 0)  //error (or underflow)
3886                return static_cast<long>(id);
3887
3888            //This is the distinguished set of ID's we use to determine
3889            //that we have exhausted the sub-element's inside the cluster
3890            //whose ID we parsed earlier.
3891
3892            if (id == 0x0F43B675)  //Cluster ID
3893                break;
3894
3895            if (id == 0x0C53BB6B)  //Cues ID
3896                break;
3897
3898            pos += len;  //consume ID (of sub-element)
3899
3900            //Read Size
3901
3902            if ((pos + 1) > avail)
3903            {
3904                len = 1;
3905                return E_BUFFER_NOT_FULL;
3906            }
3907
3908            result = GetUIntLength(m_pReader, pos, len);
3909
3910            if (result < 0)  //error
3911                return static_cast<long>(result);
3912
3913            if (result > 0)  //weird
3914                return E_BUFFER_NOT_FULL;
3915
3916            if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3917                return E_FILE_FORMAT_INVALID;
3918
3919            if ((pos + len) > avail)
3920                return E_BUFFER_NOT_FULL;
3921
3922            const long long size = ReadUInt(m_pReader, pos, len);
3923
3924            if (size < 0)  //error
3925                return static_cast<long>(size);
3926
3927            pos += len;  //consume size field of element
3928
3929            //pos now points to start of sub-element's payload
3930
3931            if (size == 0)  //weird
3932                continue;
3933
3934            const long long unknown_size = (1LL << (7 * len)) - 1;
3935
3936            if (size == unknown_size)
3937                return E_FILE_FORMAT_INVALID;  //not allowed for sub-elements
3938
3939            if ((segment_stop >= 0) && ((pos + size) > segment_stop))  //weird
3940                return E_FILE_FORMAT_INVALID;
3941
3942            pos += size;  //consume payload of sub-element
3943            assert((segment_stop < 0) || (pos <= segment_stop));
3944        }  //determine cluster size
3945
3946        cluster_size = pos - payload_pos;
3947        assert(cluster_size >= 0);  //TODO: handle cluster_size = 0
3948
3949        pos = payload_pos;  //reset and re-parse original cluster
3950    }
3951
3952    pos += cluster_size;  //consume payload
3953    assert((segment_stop < 0) || (pos <= segment_stop));
3954
3955    return 2;             //try to find a cluster that follows next
3956}
3957
3958
3959const Cluster* Segment::FindCluster(long long time_ns) const
3960{
3961    if ((m_clusters == NULL) || (m_clusterCount <= 0))
3962        return &m_eos;
3963
3964    {
3965        Cluster* const pCluster = m_clusters[0];
3966        assert(pCluster);
3967        assert(pCluster->m_index == 0);
3968
3969        if (time_ns <= pCluster->GetTime())
3970            return pCluster;
3971    }
3972
3973    //Binary search of cluster array
3974
3975    long i = 0;
3976    long j = m_clusterCount;
3977
3978    while (i < j)
3979    {
3980        //INVARIANT:
3981        //[0, i) <= time_ns
3982        //[i, j) ?
3983        //[j, m_clusterCount)  > time_ns
3984
3985        const long k = i + (j - i) / 2;
3986        assert(k < m_clusterCount);
3987
3988        Cluster* const pCluster = m_clusters[k];
3989        assert(pCluster);
3990        assert(pCluster->m_index == k);
3991
3992        const long long t = pCluster->GetTime();
3993
3994        if (t <= time_ns)
3995            i = k + 1;
3996        else
3997            j = k;
3998
3999        assert(i <= j);
4000    }
4001
4002    assert(i == j);
4003    assert(i > 0);
4004    assert(i <= m_clusterCount);
4005
4006    const long k = i - 1;
4007
4008    Cluster* const pCluster = m_clusters[k];
4009    assert(pCluster);
4010    assert(pCluster->m_index == k);
4011    assert(pCluster->GetTime() <= time_ns);
4012
4013    return pCluster;
4014}
4015
4016
4017#if 0
4018const BlockEntry* Segment::Seek(
4019    long long time_ns,
4020    const Track* pTrack) const
4021{
4022    assert(pTrack);
4023
4024    if ((m_clusters == NULL) || (m_clusterCount <= 0))
4025        return pTrack->GetEOS();
4026
4027    Cluster** const i = m_clusters;
4028    assert(i);
4029
4030    {
4031        Cluster* const pCluster = *i;
4032        assert(pCluster);
4033        assert(pCluster->m_index == 0);  //m_clusterCount > 0
4034        assert(pCluster->m_pSegment == this);
4035
4036        if (time_ns <= pCluster->GetTime())
4037            return pCluster->GetEntry(pTrack);
4038    }
4039
4040    Cluster** const j = i + m_clusterCount;
4041
4042    if (pTrack->GetType() == 2)  //audio
4043    {
4044        //TODO: we could decide to use cues for this, as we do for video.
4045        //But we only use it for video because looking around for a keyframe
4046        //can get expensive.  Audio doesn't require anything special so a
4047        //straight cluster search is good enough (we assume).
4048
4049        Cluster** lo = i;
4050        Cluster** hi = j;
4051
4052        while (lo < hi)
4053        {
4054            //INVARIANT:
4055            //[i, lo) <= time_ns
4056            //[lo, hi) ?
4057            //[hi, j)  > time_ns
4058
4059            Cluster** const mid = lo + (hi - lo) / 2;
4060            assert(mid < hi);
4061
4062            Cluster* const pCluster = *mid;
4063            assert(pCluster);
4064            assert(pCluster->m_index == long(mid - m_clusters));
4065            assert(pCluster->m_pSegment == this);
4066
4067            const long long t = pCluster->GetTime();
4068
4069            if (t <= time_ns)
4070                lo = mid + 1;
4071            else
4072                hi = mid;
4073
4074            assert(lo <= hi);
4075        }
4076
4077        assert(lo == hi);
4078        assert(lo > i);
4079        assert(lo <= j);
4080
4081        while (lo > i)
4082        {
4083            Cluster* const pCluster = *--lo;
4084            assert(pCluster);
4085            assert(pCluster->GetTime() <= time_ns);
4086
4087            const BlockEntry* const pBE = pCluster->GetEntry(pTrack);
4088
4089            if ((pBE != 0) && !pBE->EOS())
4090                return pBE;
4091
4092            //landed on empty cluster (no entries)
4093        }
4094
4095        return pTrack->GetEOS();  //weird
4096    }
4097
4098    assert(pTrack->GetType() == 1);  //video
4099
4100    Cluster** lo = i;
4101    Cluster** hi = j;
4102
4103    while (lo < hi)
4104    {
4105        //INVARIANT:
4106        //[i, lo) <= time_ns
4107        //[lo, hi) ?
4108        //[hi, j)  > time_ns
4109
4110        Cluster** const mid = lo + (hi - lo) / 2;
4111        assert(mid < hi);
4112
4113        Cluster* const pCluster = *mid;
4114        assert(pCluster);
4115
4116        const long long t = pCluster->GetTime();
4117
4118        if (t <= time_ns)
4119            lo = mid + 1;
4120        else
4121            hi = mid;
4122
4123        assert(lo <= hi);
4124    }
4125
4126    assert(lo == hi);
4127    assert(lo > i);
4128    assert(lo <= j);
4129
4130    Cluster* pCluster = *--lo;
4131    assert(pCluster);
4132    assert(pCluster->GetTime() <= time_ns);
4133
4134    {
4135        const BlockEntry* const pBE = pCluster->GetEntry(pTrack, time_ns);
4136
4137        if ((pBE != 0) && !pBE->EOS())  //found a keyframe
4138            return pBE;
4139    }
4140
4141    const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack);
4142
4143    while (lo != i)
4144    {
4145        pCluster = *--lo;
4146        assert(pCluster);
4147        assert(pCluster->GetTime() <= time_ns);
4148
4149        const BlockEntry* const pBlockEntry = pCluster->GetMaxKey(pVideo);
4150
4151        if ((pBlockEntry != 0) && !pBlockEntry->EOS())
4152            return pBlockEntry;
4153    }
4154
4155    //weird: we're on the first cluster, but no keyframe found
4156    //should never happen but we must return something anyway
4157
4158    return pTrack->GetEOS();
4159}
4160#endif
4161
4162
4163#if 0
4164bool Segment::SearchCues(
4165    long long time_ns,
4166    Track* pTrack,
4167    Cluster*& pCluster,
4168    const BlockEntry*& pBlockEntry,
4169    const CuePoint*& pCP,
4170    const CuePoint::TrackPosition*& pTP)
4171{
4172    if (pTrack->GetType() != 1)  //not video
4173        return false;  //TODO: for now, just handle video stream
4174
4175    if (m_pCues == NULL)
4176        return false;
4177
4178    if (!m_pCues->Find(time_ns, pTrack, pCP, pTP))
4179        return false;  //weird
4180
4181    assert(pCP);
4182    assert(pTP);
4183    assert(pTP->m_track == pTrack->GetNumber());
4184
4185    //We have the cue point and track position we want,
4186    //so we now need to search for the cluster having
4187    //the indicated position.
4188
4189    return GetCluster(pCP, pTP, pCluster, pBlockEntry);
4190}
4191#endif
4192
4193
4194const Tracks* Segment::GetTracks() const
4195{
4196    return m_pTracks;
4197}
4198
4199
4200const SegmentInfo* Segment::GetInfo() const
4201{
4202    return m_pInfo;
4203}
4204
4205
4206const Cues* Segment::GetCues() const
4207{
4208    return m_pCues;
4209}
4210
4211
4212const SeekHead* Segment::GetSeekHead() const
4213{
4214    return m_pSeekHead;
4215}
4216
4217
4218long long Segment::GetDuration() const
4219{
4220    assert(m_pInfo);
4221    return m_pInfo->GetDuration();
4222}
4223
4224
4225SegmentInfo::SegmentInfo(
4226    Segment* pSegment,
4227    long long start,
4228    long long size_,
4229    long long element_start,
4230    long long element_size) :
4231    m_pSegment(pSegment),
4232    m_start(start),
4233    m_size(size_),
4234    m_element_start(element_start),
4235    m_element_size(element_size),
4236    m_pMuxingAppAsUTF8(NULL),
4237    m_pWritingAppAsUTF8(NULL),
4238    m_pTitleAsUTF8(NULL)
4239{
4240}
4241
4242SegmentInfo::~SegmentInfo()
4243{
4244    delete[] m_pMuxingAppAsUTF8;
4245    m_pMuxingAppAsUTF8 = NULL;
4246
4247    delete[] m_pWritingAppAsUTF8;
4248    m_pWritingAppAsUTF8 = NULL;
4249
4250    delete[] m_pTitleAsUTF8;
4251    m_pTitleAsUTF8 = NULL;
4252}
4253
4254
4255long SegmentInfo::Parse()
4256{
4257    assert(m_pMuxingAppAsUTF8 == NULL);
4258    assert(m_pWritingAppAsUTF8 == NULL);
4259    assert(m_pTitleAsUTF8 == NULL);
4260
4261    IMkvReader* const pReader = m_pSegment->m_pReader;
4262
4263    long long pos = m_start;
4264    const long long stop = m_start + m_size;
4265
4266    m_timecodeScale = 1000000;
4267    m_duration = -1;
4268
4269    while (pos < stop)
4270    {
4271        long long id, size;
4272
4273        const long status = ParseElementHeader(
4274                                pReader,
4275                                pos,
4276                                stop,
4277                                id,
4278                                size);
4279
4280        if (status < 0)  //error
4281            return status;
4282
4283        if (id == 0x0AD7B1)  //Timecode Scale
4284        {
4285            m_timecodeScale = UnserializeUInt(pReader, pos, size);
4286
4287            if (m_timecodeScale <= 0)
4288                return E_FILE_FORMAT_INVALID;
4289        }
4290        else if (id == 0x0489)  //Segment duration
4291        {
4292            const long status = UnserializeFloat(
4293                                    pReader,
4294                                    pos,
4295                                    size,
4296                                    m_duration);
4297
4298            if (status < 0)
4299                return status;
4300
4301            if (m_duration < 0)
4302                return E_FILE_FORMAT_INVALID;
4303        }
4304        else if (id == 0x0D80)  //MuxingApp
4305        {
4306            const long status = UnserializeString(
4307                                    pReader,
4308                                    pos,
4309                                    size,
4310                                    m_pMuxingAppAsUTF8);
4311
4312            if (status)
4313                return status;
4314        }
4315        else if (id == 0x1741)  //WritingApp
4316        {
4317            const long status = UnserializeString(
4318                                    pReader,
4319                                    pos,
4320                                    size,
4321                                    m_pWritingAppAsUTF8);
4322
4323            if (status)
4324                return status;
4325        }
4326        else if (id == 0x3BA9)  //Title
4327        {
4328            const long status = UnserializeString(
4329                                    pReader,
4330                                    pos,
4331                                    size,
4332                                    m_pTitleAsUTF8);
4333
4334            if (status)
4335                return status;
4336        }
4337
4338        pos += size;
4339        assert(pos <= stop);
4340    }
4341
4342    assert(pos == stop);
4343
4344    return 0;
4345}
4346
4347
4348long long SegmentInfo::GetTimeCodeScale() const
4349{
4350    return m_timecodeScale;
4351}
4352
4353
4354long long SegmentInfo::GetDuration() const
4355{
4356    if (m_duration < 0)
4357        return -1;
4358
4359    assert(m_timecodeScale >= 1);
4360
4361    const double dd = double(m_duration) * double(m_timecodeScale);
4362    const long long d = static_cast<long long>(dd);
4363
4364    return d;
4365}
4366
4367const char* SegmentInfo::GetMuxingAppAsUTF8() const
4368{
4369    return m_pMuxingAppAsUTF8;
4370}
4371
4372
4373const char* SegmentInfo::GetWritingAppAsUTF8() const
4374{
4375    return m_pWritingAppAsUTF8;
4376}
4377
4378const char* SegmentInfo::GetTitleAsUTF8() const
4379{
4380    return m_pTitleAsUTF8;
4381}
4382
4383///////////////////////////////////////////////////////////////
4384// ContentEncoding element
4385ContentEncoding::ContentCompression::ContentCompression()
4386    : algo(0),
4387      settings(NULL) {
4388}
4389
4390ContentEncoding::ContentCompression::~ContentCompression() {
4391  delete [] settings;
4392}
4393
4394ContentEncoding::ContentEncryption::ContentEncryption()
4395    : algo(0),
4396      key_id(NULL),
4397      key_id_len(0),
4398      signature(NULL),
4399      signature_len(0),
4400      sig_key_id(NULL),
4401      sig_key_id_len(0),
4402      sig_algo(0),
4403      sig_hash_algo(0) {
4404}
4405
4406ContentEncoding::ContentEncryption::~ContentEncryption() {
4407  delete [] key_id;
4408  delete [] signature;
4409  delete [] sig_key_id;
4410}
4411
4412ContentEncoding::ContentEncoding()
4413    : compression_entries_(NULL),
4414      compression_entries_end_(NULL),
4415      encryption_entries_(NULL),
4416      encryption_entries_end_(NULL),
4417      encoding_order_(0),
4418      encoding_scope_(1),
4419      encoding_type_(0) {
4420}
4421
4422ContentEncoding::~ContentEncoding() {
4423  ContentCompression** comp_i = compression_entries_;
4424  ContentCompression** const comp_j = compression_entries_end_;
4425
4426  while (comp_i != comp_j) {
4427    ContentCompression* const comp = *comp_i++;
4428    delete comp;
4429  }
4430
4431  delete [] compression_entries_;
4432
4433  ContentEncryption** enc_i = encryption_entries_;
4434  ContentEncryption** const enc_j = encryption_entries_end_;
4435
4436  while (enc_i != enc_j) {
4437    ContentEncryption* const enc = *enc_i++;
4438    delete enc;
4439  }
4440
4441  delete [] encryption_entries_;
4442}
4443
4444
4445const ContentEncoding::ContentCompression*
4446ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
4447  const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4448  assert(count >= 0);
4449
4450  if (idx >= static_cast<unsigned long>(count))
4451    return NULL;
4452
4453  return compression_entries_[idx];
4454}
4455
4456unsigned long ContentEncoding::GetCompressionCount() const {
4457  const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4458  assert(count >= 0);
4459
4460  return static_cast<unsigned long>(count);
4461}
4462
4463const ContentEncoding::ContentEncryption*
4464ContentEncoding::GetEncryptionByIndex(unsigned long idx) const {
4465  const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4466  assert(count >= 0);
4467
4468  if (idx >= static_cast<unsigned long>(count))
4469    return NULL;
4470
4471  return encryption_entries_[idx];
4472}
4473
4474unsigned long ContentEncoding::GetEncryptionCount() const {
4475  const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4476  assert(count >= 0);
4477
4478  return static_cast<unsigned long>(count);
4479}
4480
4481void ContentEncoding::ParseEncryptionEntry(
4482    long long start,
4483    long long size,
4484    IMkvReader* const pReader,
4485    ContentEncryption* const encryption) {
4486  assert(pReader);
4487  assert(encryption);
4488
4489  long long pos = start;
4490  const long long stop = start + size;
4491
4492  while (pos < stop) {
4493#ifdef _DEBUG
4494    long len;
4495    const long long id = ReadUInt(pReader, pos, len);
4496    assert(id >= 0);  //TODO: handle error case
4497    assert((pos + len) <= stop);
4498#endif
4499
4500    long long value;
4501    unsigned char* buf;
4502    size_t buf_len;
4503
4504    if (Match(pReader, pos, 0x7E1, value)) {
4505      // ContentEncAlgo
4506      encryption->algo = value;
4507    } else if (Match(pReader, pos, 0x7E2, buf, buf_len)) {
4508      // ContentEncKeyID
4509      encryption->key_id = buf;
4510      encryption->key_id_len = buf_len;
4511    } else if (Match(pReader, pos, 0x7E3, buf, buf_len)) {
4512      // ContentSignature
4513      encryption->signature = buf;
4514      encryption->signature_len = buf_len;
4515    } else if (Match(pReader, pos, 0x7E4, buf, buf_len)) {
4516      // ContentSigKeyID
4517      encryption->sig_key_id = buf;
4518      encryption->sig_key_id_len = buf_len;
4519    } else if (Match(pReader, pos, 0x7E5, value)) {
4520      // ContentSigAlgo
4521      encoding_type_ = value;
4522    } else if (Match(pReader, pos, 0x7E6, value)) {
4523      // ContentSigHashAlgo
4524      encoding_type_ = value;
4525    } else {
4526      long len;
4527      const long long id = ReadUInt(pReader, pos, len);
4528      assert(id >= 0);  //TODO: handle error case
4529      assert((pos + len) <= stop);
4530
4531      pos += len;  //consume id
4532
4533      const long long size = ReadUInt(pReader, pos, len);
4534      assert(size >= 0);  //TODO: handle error case
4535      assert((pos + len) <= stop);
4536
4537      pos += len;  //consume length of size
4538      assert((pos + size) <= stop);
4539
4540      pos += size;  //consume payload
4541      assert(pos <= stop);
4542    }
4543  }
4544}
4545
4546bool ContentEncoding::ParseContentEncodingEntry(long long start,
4547                                                long long size,
4548                                                IMkvReader* const pReader) {
4549  assert(pReader);
4550
4551  long long pos = start;
4552  const long long stop = start + size;
4553
4554  // Count ContentCompression and ContentEncryption elements.
4555  long long pos1 = start;
4556  int compression_count = 0;
4557  int encryption_count = 0;
4558
4559  while (pos1 < stop) {
4560    long len;
4561    const long long id = ReadUInt(pReader, pos1, len);
4562    assert(id >= 0);
4563    assert((pos1 + len) <= stop);
4564
4565    pos1 += len;  //consume id
4566
4567    const long long size = ReadUInt(pReader, pos1, len);
4568    assert(size >= 0);
4569    assert((pos1 + len) <= stop);
4570
4571    pos1 += len;  //consume length of size
4572
4573    //pos now designates start of element
4574    if (id == 0x1034)  // ContentCompression ID
4575      ++compression_count;
4576
4577    if (id == 0x1035)  // ContentEncryption ID
4578      ++encryption_count;
4579
4580    pos1 += size;  //consume payload
4581    assert(pos1 <= stop);
4582  }
4583
4584  if (compression_count <= 0 && encryption_count <= 0)
4585    return false;
4586
4587  if (compression_count > 0) {
4588    compression_entries_ = new ContentCompression*[compression_count];
4589    compression_entries_end_ = compression_entries_;
4590  }
4591
4592  if (encryption_count > 0) {
4593    encryption_entries_ = new ContentEncryption*[encryption_count];
4594    encryption_entries_end_ = encryption_entries_;
4595  }
4596
4597  while (pos < stop) {
4598#ifdef _DEBUG
4599    long len;
4600    const long long id = ReadUInt(pReader, pos, len);
4601    assert(id >= 0);  //TODO: handle error case
4602    assert((pos + len) <= stop);
4603#endif
4604
4605    long long value;
4606    if (Match(pReader, pos, 0x1031, value)) {
4607      // ContentEncodingOrder
4608      encoding_order_ = value;
4609    } else if (Match(pReader, pos, 0x1032, value)) {
4610      // ContentEncodingScope
4611      encoding_scope_ = value;
4612      assert(encoding_scope_ > 0);
4613    } else if (Match(pReader, pos, 0x1033, value)) {
4614      // ContentEncodingType
4615      encoding_type_ = value;
4616    } else {
4617      long len;
4618      const long long id = ReadUInt(pReader, pos, len);
4619      assert(id >= 0);  //TODO: handle error case
4620      assert((pos + len) <= stop);
4621
4622      pos += len;  //consume id
4623
4624      const long long size = ReadUInt(pReader, pos, len);
4625      assert(size >= 0);  //TODO: handle error case
4626      assert((pos + len) <= stop);
4627
4628      pos += len;  //consume length of size
4629      assert((pos + size) <= stop);
4630
4631      //pos now designates start of payload
4632
4633      if (id == 0x1034) {
4634        // ContentCompression ID
4635        // TODO(fgaligan): Add code to parse ContentCompression elements.
4636      } else if (id == 0x1035) {
4637        // ContentEncryption ID
4638        ContentEncryption* const encryption = new ContentEncryption();
4639
4640        ParseEncryptionEntry(pos, size, pReader, encryption);
4641        *encryption_entries_end_ = encryption;
4642        ++encryption_entries_end_;
4643      }
4644
4645      pos += size;  //consume payload
4646      assert(pos <= stop);
4647    }
4648  }
4649
4650  assert(pos == stop);
4651
4652  return true;
4653}
4654
4655Track::Track(
4656    Segment* pSegment,
4657    long long element_start,
4658    long long element_size) :
4659    m_pSegment(pSegment),
4660    m_element_start(element_start),
4661    m_element_size(element_size),
4662    content_encoding_entries_(NULL),
4663    content_encoding_entries_end_(NULL)
4664{
4665}
4666
4667Track::~Track()
4668{
4669    Info& info = const_cast<Info&>(m_info);
4670    info.Clear();
4671
4672    ContentEncoding** i = content_encoding_entries_;
4673    ContentEncoding** const j = content_encoding_entries_end_;
4674
4675    while (i != j) {
4676        ContentEncoding* const encoding = *i++;
4677        delete encoding;
4678    }
4679
4680    delete [] content_encoding_entries_;
4681}
4682
4683Track::Info::Info():
4684    nameAsUTF8(NULL),
4685    codecId(NULL),
4686    codecNameAsUTF8(NULL),
4687    codecPrivate(NULL),
4688    codecPrivateSize(0)
4689{
4690}
4691
4692Track::Info::~Info()
4693{
4694    Clear();
4695}
4696
4697void Track::Info::Clear()
4698{
4699    delete[] nameAsUTF8;
4700    nameAsUTF8 = NULL;
4701
4702    delete[] codecId;
4703    codecId = NULL;
4704
4705    delete[] codecPrivate;
4706    codecPrivate = NULL;
4707    codecPrivateSize = 0;
4708
4709    delete[] codecNameAsUTF8;
4710    codecNameAsUTF8 = NULL;
4711}
4712
4713int Track::Info::CopyStr(char* Info::*str, Info& dst_) const
4714{
4715    if (str == static_cast<char* Info::*>(NULL))
4716        return -1;
4717
4718    char*& dst = dst_.*str;
4719
4720    if (dst)  //should be NULL already
4721        return -1;
4722
4723    const char* const src = this->*str;
4724
4725    if (src == NULL)
4726        return 0;
4727
4728    const size_t len = strlen(src);
4729
4730    dst = new (std::nothrow) char[len+1];
4731
4732    if (dst == NULL)
4733        return -1;
4734
4735    strcpy(dst, src);
4736
4737    return 0;
4738}
4739
4740
4741int Track::Info::Copy(Info& dst) const
4742{
4743    if (&dst == this)
4744        return 0;
4745
4746    dst.type = type;
4747    dst.number = number;
4748    dst.uid = uid;
4749    dst.lacing = lacing;
4750    dst.settings = settings;
4751
4752    //We now copy the string member variables from src to dst.
4753    //This involves memory allocation so in principle the operation
4754    //can fail (indeed, that's why we have Info::Copy), so we must
4755    //report this to the caller.  An error return from this function
4756    //therefore implies that the copy was only partially successful.
4757
4758    if (int status = CopyStr(&Info::nameAsUTF8, dst))
4759        return status;
4760
4761    if (int status = CopyStr(&Info::codecId, dst))
4762        return status;
4763
4764    if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
4765        return status;
4766
4767    if (codecPrivateSize > 0)
4768    {
4769        if (codecPrivate == NULL)
4770            return -1;
4771
4772        if (dst.codecPrivate)
4773            return -1;
4774
4775        if (dst.codecPrivateSize != 0)
4776            return -1;
4777
4778        dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize];
4779
4780        if (dst.codecPrivate == NULL)
4781            return -1;
4782
4783        memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
4784        dst.codecPrivateSize = codecPrivateSize;
4785    }
4786
4787    return 0;
4788}
4789
4790const BlockEntry* Track::GetEOS() const
4791{
4792    return &m_eos;
4793}
4794
4795long Track::GetType() const
4796{
4797    return m_info.type;
4798}
4799
4800long Track::GetNumber() const
4801{
4802    return m_info.number;
4803}
4804
4805unsigned long long Track::GetUid() const
4806{
4807    return m_info.uid;
4808}
4809
4810const char* Track::GetNameAsUTF8() const
4811{
4812    return m_info.nameAsUTF8;
4813}
4814
4815const char* Track::GetCodecNameAsUTF8() const
4816{
4817    return m_info.codecNameAsUTF8;
4818}
4819
4820
4821const char* Track::GetCodecId() const
4822{
4823    return m_info.codecId;
4824}
4825
4826const unsigned char* Track::GetCodecPrivate(size_t& size) const
4827{
4828    size = m_info.codecPrivateSize;
4829    return m_info.codecPrivate;
4830}
4831
4832
4833bool Track::GetLacing() const
4834{
4835    return m_info.lacing;
4836}
4837
4838
4839long Track::GetFirst(const BlockEntry*& pBlockEntry) const
4840{
4841    const Cluster* pCluster = m_pSegment->GetFirst();
4842
4843    for (int i = 0; ; )
4844    {
4845        if (pCluster == NULL)
4846        {
4847            pBlockEntry = GetEOS();
4848            return 1;
4849        }
4850
4851        if (pCluster->EOS())
4852        {
4853#if 0
4854            if (m_pSegment->Unparsed() <= 0)  //all clusters have been loaded
4855            {
4856                pBlockEntry = GetEOS();
4857                return 1;
4858            }
4859#else
4860            if (m_pSegment->DoneParsing())
4861            {
4862                pBlockEntry = GetEOS();
4863                return 1;
4864            }
4865#endif
4866
4867            pBlockEntry = 0;
4868            return E_BUFFER_NOT_FULL;
4869        }
4870
4871        long status = pCluster->GetFirst(pBlockEntry);
4872
4873        if (status < 0)  //error
4874            return status;
4875
4876        if (pBlockEntry == 0)  //empty cluster
4877        {
4878            pCluster = m_pSegment->GetNext(pCluster);
4879            continue;
4880        }
4881
4882        for (;;)
4883        {
4884            const Block* const pBlock = pBlockEntry->GetBlock();
4885            assert(pBlock);
4886
4887            const long long tn = pBlock->GetTrackNumber();
4888
4889            if ((tn == m_info.number) && VetEntry(pBlockEntry))
4890                return 0;
4891
4892            const BlockEntry* pNextEntry;
4893
4894            status = pCluster->GetNext(pBlockEntry, pNextEntry);
4895
4896            if (status < 0)  //error
4897                return status;
4898
4899            if (pNextEntry == 0)
4900                break;
4901
4902            pBlockEntry = pNextEntry;
4903        }
4904
4905        ++i;
4906
4907        if (i >= 100)
4908            break;
4909
4910        pCluster = m_pSegment->GetNext(pCluster);
4911    }
4912
4913    //NOTE: if we get here, it means that we didn't find a block with
4914    //a matching track number.  We interpret that as an error (which
4915    //might be too conservative).
4916
4917    pBlockEntry = GetEOS();  //so we can return a non-NULL value
4918    return 1;
4919}
4920
4921
4922long Track::GetNext(
4923    const BlockEntry* pCurrEntry,
4924    const BlockEntry*& pNextEntry) const
4925{
4926    assert(pCurrEntry);
4927    assert(!pCurrEntry->EOS());  //?
4928
4929    const Block* const pCurrBlock = pCurrEntry->GetBlock();
4930    assert(pCurrBlock->GetTrackNumber() == m_info.number);
4931
4932    const Cluster* pCluster = pCurrEntry->GetCluster();
4933    assert(pCluster);
4934    assert(!pCluster->EOS());
4935
4936    long status = pCluster->GetNext(pCurrEntry, pNextEntry);
4937
4938    if (status < 0)  //error
4939        return status;
4940
4941    for (int i = 0; ; )
4942    {
4943        while (pNextEntry)
4944        {
4945            const Block* const pNextBlock = pNextEntry->GetBlock();
4946            assert(pNextBlock);
4947
4948            if (pNextBlock->GetTrackNumber() == m_info.number)
4949                return 0;
4950
4951            pCurrEntry = pNextEntry;
4952
4953            status = pCluster->GetNext(pCurrEntry, pNextEntry);
4954
4955            if (status < 0) //error
4956                return status;
4957        }
4958
4959        pCluster = m_pSegment->GetNext(pCluster);
4960
4961        if (pCluster == NULL)
4962        {
4963            pNextEntry = GetEOS();
4964            return 1;
4965        }
4966
4967        if (pCluster->EOS())
4968        {
4969#if 0
4970            if (m_pSegment->Unparsed() <= 0)   //all clusters have been loaded
4971            {
4972                pNextEntry = GetEOS();
4973                return 1;
4974            }
4975#else
4976            if (m_pSegment->DoneParsing())
4977            {
4978                pNextEntry = GetEOS();
4979                return 1;
4980            }
4981#endif
4982
4983            //TODO: there is a potential O(n^2) problem here: we tell the
4984            //caller to (pre)load another cluster, which he does, but then he
4985            //calls GetNext again, which repeats the same search.  This is
4986            //a pathological case, since the only way it can happen is if
4987            //there exists a long sequence of clusters none of which contain a
4988            // block from this track.  One way around this problem is for the
4989            //caller to be smarter when he loads another cluster: don't call
4990            //us back until you have a cluster that contains a block from this
4991            //track. (Of course, that's not cheap either, since our caller
4992            //would have to scan the each cluster as it's loaded, so that
4993            //would just push back the problem.)
4994
4995            pNextEntry = NULL;
4996            return E_BUFFER_NOT_FULL;
4997        }
4998
4999        status = pCluster->GetFirst(pNextEntry);
5000
5001        if (status < 0)  //error
5002            return status;
5003
5004        if (pNextEntry == NULL)  //empty cluster
5005            continue;
5006
5007        ++i;
5008
5009        if (i >= 100)
5010            break;
5011    }
5012
5013    //NOTE: if we get here, it means that we didn't find a block with
5014    //a matching track number after lots of searching, so we give
5015    //up trying.
5016
5017    pNextEntry = GetEOS();  //so we can return a non-NULL value
5018    return 1;
5019}
5020
5021const ContentEncoding*
5022Track::GetContentEncodingByIndex(unsigned long idx) const {
5023  const ptrdiff_t count =
5024      content_encoding_entries_end_ - content_encoding_entries_;
5025  assert(count >= 0);
5026
5027  if (idx >= static_cast<unsigned long>(count))
5028    return NULL;
5029
5030  return content_encoding_entries_[idx];
5031}
5032
5033unsigned long Track::GetContentEncodingCount() const {
5034  const ptrdiff_t count =
5035      content_encoding_entries_end_ - content_encoding_entries_;
5036  assert(count >= 0);
5037
5038  return static_cast<unsigned long>(count);
5039}
5040
5041void Track::ParseContentEncodingsEntry(long long start, long long size) {
5042  IMkvReader* const pReader = m_pSegment->m_pReader;
5043  assert(pReader);
5044
5045  long long pos = start;
5046  const long long stop = start + size;
5047
5048  // Count ContentEncoding elements.
5049  long long pos1 = start;
5050  int count = 0;
5051
5052  while (pos1 < stop) {
5053    long len;
5054    const long long id = ReadUInt(pReader, pos1, len);
5055    assert(id >= 0);
5056    assert((pos1 + len) <= stop);
5057
5058    pos1 += len;  //consume id
5059
5060    const long long size = ReadUInt(pReader, pos1, len);
5061    assert(size >= 0);
5062    assert((pos1 + len) <= stop);
5063
5064    pos1 += len;  //consume length of size
5065
5066    //pos now designates start of element
5067    if (id == 0x2240)  // ContentEncoding ID
5068      ++count;
5069
5070    pos1 += size;  //consume payload
5071    assert(pos1 <= stop);
5072  }
5073
5074  if (count <= 0)
5075    return;
5076
5077  content_encoding_entries_ = new ContentEncoding*[count];
5078  content_encoding_entries_end_ = content_encoding_entries_;
5079
5080  while (pos < stop) {
5081    long len;
5082    const long long id = ReadUInt(pReader, pos, len);
5083    assert(id >= 0);
5084    assert((pos + len) <= stop);
5085
5086    pos += len;  //consume id
5087
5088    const long long size1 = ReadUInt(pReader, pos, len);
5089    assert(size1 >= 0);
5090    assert((pos + len) <= stop);
5091
5092    pos += len;  //consume length of size
5093
5094    //pos now designates start of element
5095    if (id == 0x2240) { // ContentEncoding ID
5096      ContentEncoding* const content_encoding = new ContentEncoding();
5097
5098      if (!content_encoding->ParseContentEncodingEntry(pos, size1, pReader)) {
5099        delete content_encoding;
5100      } else {
5101        *content_encoding_entries_end_ = content_encoding;
5102        ++content_encoding_entries_end_;
5103      }
5104    }
5105
5106    pos += size1;  //consume payload
5107    assert(pos <= stop);
5108  }
5109
5110  assert(pos == stop);
5111
5112  return;
5113}
5114
5115Track::EOSBlock::EOSBlock() :
5116    BlockEntry(NULL, LONG_MIN)
5117{
5118}
5119
5120BlockEntry::Kind Track::EOSBlock::GetKind() const
5121{
5122    return kBlockEOS;
5123}
5124
5125
5126const Block* Track::EOSBlock::GetBlock() const
5127{
5128    return NULL;
5129}
5130
5131
5132VideoTrack::VideoTrack(
5133    Segment* pSegment,
5134    long long element_start,
5135    long long element_size) :
5136    Track(pSegment, element_start, element_size)
5137{
5138}
5139
5140
5141long VideoTrack::Parse(
5142    Segment* pSegment,
5143    const Info& i,
5144    long long elem_st,
5145    long long elem_sz,
5146    VideoTrack*& pTrack)
5147{
5148    if (pTrack)
5149        return -1;
5150
5151    if (i.type != Track::kVideo)
5152        return -1;
5153
5154    long long width = 0;
5155    long long height = 0;
5156    double rate = 0.0;
5157
5158    IMkvReader* const pReader = pSegment->m_pReader;
5159
5160    const Settings& s = i.settings;
5161    assert(s.start >= 0);
5162    assert(s.size >= 0);
5163
5164    long long pos = s.start;
5165    assert(pos >= 0);
5166
5167    const long long stop = pos + s.size;
5168
5169    while (pos < stop)
5170    {
5171        long long id, size;
5172
5173        const long status = ParseElementHeader(
5174                                pReader,
5175                                pos,
5176                                stop,
5177                                id,
5178                                size);
5179
5180        if (status < 0)  //error
5181            return status;
5182
5183        if (id == 0x30)  //pixel width
5184        {
5185            width = UnserializeUInt(pReader, pos, size);
5186
5187            if (width <= 0)
5188                return E_FILE_FORMAT_INVALID;
5189        }
5190        else if (id == 0x3A)  //pixel height
5191        {
5192            height = UnserializeUInt(pReader, pos, size);
5193
5194            if (height <= 0)
5195                return E_FILE_FORMAT_INVALID;
5196        }
5197        else if (id == 0x0383E3)  //frame rate
5198        {
5199            const long status = UnserializeFloat(
5200                                    pReader,
5201                                    pos,
5202                                    size,
5203                                    rate);
5204
5205            if (status < 0)
5206                return status;
5207
5208            if (rate <= 0)
5209                return E_FILE_FORMAT_INVALID;
5210        }
5211
5212        pos += size;  //consume payload
5213        assert(pos <= stop);
5214    }
5215
5216    assert(pos == stop);
5217
5218    pTrack = new (std::nothrow) VideoTrack(pSegment, elem_st, elem_sz);
5219
5220    if (pTrack == NULL)
5221        return -1;  //generic error
5222
5223    const int status = i.Copy(pTrack->m_info);
5224
5225    if (status)
5226        return status;
5227
5228    pTrack->m_width = width;
5229    pTrack->m_height = height;
5230    pTrack->m_rate = rate;
5231
5232    return 0;  //success
5233}
5234
5235
5236bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const
5237{
5238    assert(pBlockEntry);
5239
5240    const Block* const pBlock = pBlockEntry->GetBlock();
5241    assert(pBlock);
5242    assert(pBlock->GetTrackNumber() == m_info.number);
5243
5244    return pBlock->IsKey();
5245}
5246
5247
5248long VideoTrack::Seek(
5249    long long time_ns,
5250    const BlockEntry*& pResult) const
5251{
5252    const long status = GetFirst(pResult);
5253
5254    if (status < 0)  //buffer underflow, etc
5255        return status;
5256
5257    assert(pResult);
5258
5259    if (pResult->EOS())
5260        return 0;
5261
5262    const Cluster* pCluster = pResult->GetCluster();
5263    assert(pCluster);
5264    assert(pCluster->GetIndex() >= 0);
5265
5266    if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5267        return 0;
5268
5269    Cluster** const clusters = m_pSegment->m_clusters;
5270    assert(clusters);
5271
5272    const long count = m_pSegment->GetCount();  //loaded only, not pre-loaded
5273    assert(count > 0);
5274
5275    Cluster** const i = clusters + pCluster->GetIndex();
5276    assert(i);
5277    assert(*i == pCluster);
5278    assert(pCluster->GetTime() <= time_ns);
5279
5280    Cluster** const j = clusters + count;
5281
5282    Cluster** lo = i;
5283    Cluster** hi = j;
5284
5285    while (lo < hi)
5286    {
5287        //INVARIANT:
5288        //[i, lo) <= time_ns
5289        //[lo, hi) ?
5290        //[hi, j)  > time_ns
5291
5292        Cluster** const mid = lo + (hi - lo) / 2;
5293        assert(mid < hi);
5294
5295        pCluster = *mid;
5296        assert(pCluster);
5297        assert(pCluster->GetIndex() >= 0);
5298        assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5299
5300        const long long t = pCluster->GetTime();
5301
5302        if (t <= time_ns)
5303            lo = mid + 1;
5304        else
5305            hi = mid;
5306
5307        assert(lo <= hi);
5308    }
5309
5310    assert(lo == hi);
5311    assert(lo > i);
5312    assert(lo <= j);
5313
5314    pCluster = *--lo;
5315    assert(pCluster);
5316    assert(pCluster->GetTime() <= time_ns);
5317
5318    pResult = pCluster->GetEntry(this, time_ns);
5319
5320    if ((pResult != 0) && !pResult->EOS())  //found a keyframe
5321        return 0;
5322
5323    while (lo != i)
5324    {
5325        pCluster = *--lo;
5326        assert(pCluster);
5327        assert(pCluster->GetTime() <= time_ns);
5328
5329#if 0
5330        //TODO:
5331        //We need to handle the case when a cluster
5332        //contains multiple keyframes.  Simply returning
5333        //the largest keyframe on the cluster isn't
5334        //good enough.
5335        pResult = pCluster->GetMaxKey(this);
5336#else
5337        pResult = pCluster->GetEntry(this, time_ns);
5338#endif
5339
5340        if ((pResult != 0) && !pResult->EOS())
5341            return 0;
5342    }
5343
5344    //weird: we're on the first cluster, but no keyframe found
5345    //should never happen but we must return something anyway
5346
5347    pResult = GetEOS();
5348    return 0;
5349}
5350
5351
5352long long VideoTrack::GetWidth() const
5353{
5354    return m_width;
5355}
5356
5357
5358long long VideoTrack::GetHeight() const
5359{
5360    return m_height;
5361}
5362
5363
5364double VideoTrack::GetFrameRate() const
5365{
5366    return m_rate;
5367}
5368
5369
5370AudioTrack::AudioTrack(
5371    Segment* pSegment,
5372    long long element_start,
5373    long long element_size) :
5374    Track(pSegment, element_start, element_size)
5375{
5376}
5377
5378
5379long AudioTrack::Parse(
5380    Segment* pSegment,
5381    const Info& i,
5382    long long elem_st,
5383    long long elem_sz,
5384    AudioTrack*& pTrack)
5385{
5386    if (pTrack)
5387        return -1;
5388
5389    if (i.type != Track::kAudio)
5390        return -1;
5391
5392    IMkvReader* const pReader = pSegment->m_pReader;
5393
5394    const Settings& s = i.settings;
5395    assert(s.start >= 0);
5396    assert(s.size >= 0);
5397
5398    long long pos = s.start;
5399    assert(pos >= 0);
5400
5401    const long long stop = pos + s.size;
5402
5403    double rate = 8000.0;
5404    long long channels = 1;
5405    long long bit_depth = 0;
5406
5407    while (pos < stop)
5408    {
5409        long long id, size;
5410
5411        long status = ParseElementHeader(
5412                                pReader,
5413                                pos,
5414                                stop,
5415                                id,
5416                                size);
5417
5418        if (status < 0)  //error
5419            return status;
5420
5421        if (id == 0x35)  //Sample Rate
5422        {
5423            status = UnserializeFloat(pReader, pos, size, rate);
5424
5425            if (status < 0)
5426                return status;
5427
5428            if (rate <= 0)
5429                return E_FILE_FORMAT_INVALID;
5430        }
5431        else if (id == 0x1F)  //Channel Count
5432        {
5433            channels = UnserializeUInt(pReader, pos, size);
5434
5435            if (channels <= 0)
5436                return E_FILE_FORMAT_INVALID;
5437        }
5438        else if (id == 0x2264)  //Bit Depth
5439        {
5440            bit_depth = UnserializeUInt(pReader, pos, size);
5441
5442            if (bit_depth <= 0)
5443                return E_FILE_FORMAT_INVALID;
5444        }
5445
5446        pos += size;  //consume payload
5447        assert(pos <= stop);
5448    }
5449
5450    assert(pos == stop);
5451
5452    pTrack = new (std::nothrow) AudioTrack(pSegment, elem_st, elem_sz);
5453
5454    if (pTrack == NULL)
5455        return -1;  //generic error
5456
5457    const int status = i.Copy(pTrack->m_info);
5458
5459    if (status)
5460        return status;
5461
5462    pTrack->m_rate = rate;
5463    pTrack->m_channels = channels;
5464    pTrack->m_bitDepth = bit_depth;
5465
5466    return 0;  //success
5467}
5468
5469
5470bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const
5471{
5472    assert(pBlockEntry);
5473
5474    const Block* const pBlock = pBlockEntry->GetBlock();
5475    assert(pBlock);
5476    assert(pBlock->GetTrackNumber() == m_info.number);
5477
5478    return true;
5479}
5480
5481
5482long AudioTrack::Seek(
5483    long long time_ns,
5484    const BlockEntry*& pResult) const
5485{
5486    const long status = GetFirst(pResult);
5487
5488    if (status < 0)  //buffer underflow, etc
5489        return status;
5490
5491    assert(pResult);
5492
5493    if (pResult->EOS())
5494        return 0;
5495
5496    const Cluster* pCluster = pResult->GetCluster();
5497    assert(pCluster);
5498    assert(pCluster->GetIndex() >= 0);
5499
5500    if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5501        return 0;
5502
5503    Cluster** const clusters = m_pSegment->m_clusters;
5504    assert(clusters);
5505
5506    const long count = m_pSegment->GetCount();  //loaded only, not preloaded
5507    assert(count > 0);
5508
5509    Cluster** const i = clusters + pCluster->GetIndex();
5510    assert(i);
5511    assert(*i == pCluster);
5512    assert(pCluster->GetTime() <= time_ns);
5513
5514    Cluster** const j = clusters + count;
5515
5516    Cluster** lo = i;
5517    Cluster** hi = j;
5518
5519    while (lo < hi)
5520    {
5521        //INVARIANT:
5522        //[i, lo) <= time_ns
5523        //[lo, hi) ?
5524        //[hi, j)  > time_ns
5525
5526        Cluster** const mid = lo + (hi - lo) / 2;
5527        assert(mid < hi);
5528
5529        pCluster = *mid;
5530        assert(pCluster);
5531        assert(pCluster->GetIndex() >= 0);
5532        assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5533
5534        const long long t = pCluster->GetTime();
5535
5536        if (t <= time_ns)
5537            lo = mid + 1;
5538        else
5539            hi = mid;
5540
5541        assert(lo <= hi);
5542    }
5543
5544    assert(lo == hi);
5545    assert(lo > i);
5546    assert(lo <= j);
5547
5548    while (lo > i)
5549    {
5550        pCluster = *--lo;
5551        assert(pCluster);
5552        assert(pCluster->GetTime() <= time_ns);
5553
5554        pResult = pCluster->GetEntry(this);
5555
5556        if ((pResult != 0) && !pResult->EOS())
5557            return 0;
5558
5559        //landed on empty cluster (no entries)
5560    }
5561
5562    pResult = GetEOS();  //weird
5563    return 0;
5564}
5565
5566
5567double AudioTrack::GetSamplingRate() const
5568{
5569    return m_rate;
5570}
5571
5572
5573long long AudioTrack::GetChannels() const
5574{
5575    return m_channels;
5576}
5577
5578long long AudioTrack::GetBitDepth() const
5579{
5580    return m_bitDepth;
5581}
5582
5583Tracks::Tracks(
5584    Segment* pSegment,
5585    long long start,
5586    long long size_,
5587    long long element_start,
5588    long long element_size) :
5589    m_pSegment(pSegment),
5590    m_start(start),
5591    m_size(size_),
5592    m_element_start(element_start),
5593    m_element_size(element_size),
5594    m_trackEntries(NULL),
5595    m_trackEntriesEnd(NULL)
5596{
5597}
5598
5599
5600long Tracks::Parse()
5601{
5602    assert(m_trackEntries == NULL);
5603    assert(m_trackEntriesEnd == NULL);
5604
5605    const long long stop = m_start + m_size;
5606    IMkvReader* const pReader = m_pSegment->m_pReader;
5607
5608    int count = 0;
5609    long long pos = m_start;
5610
5611    while (pos < stop)
5612    {
5613        long long id, size;
5614
5615        const long status = ParseElementHeader(
5616                                pReader,
5617                                pos,
5618                                stop,
5619                                id,
5620                                size);
5621
5622        if (status < 0)  //error
5623            return status;
5624
5625        if (size == 0)  //weird
5626            continue;
5627
5628        if (id == 0x2E)  //TrackEntry ID
5629            ++count;
5630
5631        pos += size;  //consume payload
5632        assert(pos <= stop);
5633    }
5634
5635    assert(pos == stop);
5636
5637    if (count <= 0)
5638        return 0;  //success
5639
5640    m_trackEntries = new (std::nothrow) Track*[count];
5641
5642    if (m_trackEntries == NULL)
5643        return -1;
5644
5645    m_trackEntriesEnd = m_trackEntries;
5646
5647    pos = m_start;
5648
5649    while (pos < stop)
5650    {
5651        const long long element_start = pos;
5652
5653        long long id, payload_size;
5654
5655        const long status = ParseElementHeader(
5656                                pReader,
5657                                pos,
5658                                stop,
5659                                id,
5660                                payload_size);
5661
5662        if (status < 0)  //error
5663            return status;
5664
5665        if (payload_size == 0)  //weird
5666            continue;
5667
5668        const long long payload_stop = pos + payload_size;
5669        assert(payload_stop <= stop);  //checked in ParseElement
5670
5671        const long long element_size = payload_stop - element_start;
5672
5673        if (id == 0x2E)  //TrackEntry ID
5674        {
5675            Track*& pTrack = *m_trackEntriesEnd;
5676            pTrack = NULL;
5677
5678            const long status = ParseTrackEntry(
5679                                    pos,
5680                                    payload_size,
5681                                    element_start,
5682                                    element_size,
5683                                    pTrack);
5684
5685            if (status)
5686                return status;
5687
5688            if (pTrack)
5689                ++m_trackEntriesEnd;
5690        }
5691
5692        pos = payload_stop;
5693        assert(pos <= stop);
5694    }
5695
5696    assert(pos == stop);
5697
5698    return 0;  //success
5699}
5700
5701
5702unsigned long Tracks::GetTracksCount() const
5703{
5704    const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
5705    assert(result >= 0);
5706
5707    return static_cast<unsigned long>(result);
5708}
5709
5710long Tracks::ParseTrackEntry(
5711    long long track_start,
5712    long long track_size,
5713    long long elem_st,
5714    long long elem_sz,
5715    Track*& pTrack) const
5716{
5717    if (pTrack)
5718        return -1;
5719
5720    IMkvReader* const pReader = m_pSegment->m_pReader;
5721
5722    long long pos = track_start;
5723    const long long track_stop = track_start + track_size;
5724
5725    Track::Info i;
5726
5727    i.type = 0;
5728    i.number = 0;
5729    i.uid = 0;
5730
5731    Track::Settings v;
5732    v.start = -1;
5733    v.size = -1;
5734
5735    Track::Settings a;
5736    a.start = -1;
5737    a.size = -1;
5738
5739    Track::Settings e;  //content_encodings_settings;
5740    e.start = -1;
5741    e.size = -1;
5742
5743    long long lacing = 1;  //default is true
5744
5745    while (pos < track_stop)
5746    {
5747        long long id, size;
5748
5749        const long status = ParseElementHeader(
5750                                pReader,
5751                                pos,
5752                                track_stop,
5753                                id,
5754                                size);
5755
5756        if (status < 0)  //error
5757            return status;
5758
5759        const long long start = pos;
5760
5761        if (id == 0x60)  // VideoSettings ID
5762        {
5763            if (size <= 0)
5764                return E_FILE_FORMAT_INVALID;
5765
5766            v.start = start;
5767            v.size = size;
5768        }
5769        else if (id == 0x61)  // AudioSettings ID
5770        {
5771            if (size <= 0)
5772                return E_FILE_FORMAT_INVALID;
5773
5774            a.start = start;
5775            a.size = size;
5776        }
5777        else if (id == 0x2D80) // ContentEncodings ID
5778        {
5779            if (size <= 0)
5780                return E_FILE_FORMAT_INVALID;
5781
5782            e.start = start;
5783            e.size = size;
5784        }
5785        else if (id == 0x33C5)  //Track UID
5786        {
5787            if ((size <= 0) || (size > 8))
5788                return E_FILE_FORMAT_INVALID;
5789
5790            i.uid = 0;
5791
5792            long long pos_ = start;
5793            const long long pos_end = start + size;
5794
5795            while (pos_ != pos_end)
5796            {
5797                unsigned char b;
5798
5799                const int status = pReader->Read(pos_, 1, &b);
5800
5801                if (status)
5802                    return status;
5803
5804                i.uid <<= 8;
5805                i.uid |= b;
5806
5807                ++pos_;
5808            }
5809        }
5810        else if (id == 0x57)  //Track Number
5811        {
5812            const long long num = UnserializeUInt(pReader, pos, size);
5813
5814            if ((num <= 0) || (num > 127))
5815                return E_FILE_FORMAT_INVALID;
5816
5817            i.number = static_cast<long>(num);
5818        }
5819        else if (id == 0x03)  //Track Type
5820        {
5821            const long long type = UnserializeUInt(pReader, pos, size);
5822
5823            if ((type <= 0) || (type > 254))
5824                return E_FILE_FORMAT_INVALID;
5825
5826            i.type = static_cast<long>(type);
5827        }
5828        else if (id == 0x136E)  //Track Name
5829        {
5830            const long status = UnserializeString(
5831                                    pReader,
5832                                    pos,
5833                                    size,
5834                                    i.nameAsUTF8);
5835
5836            if (status)
5837                return status;
5838        }
5839        else if (id == 0x06)  //CodecID
5840        {
5841            const long status = UnserializeString(
5842                                    pReader,
5843                                    pos,
5844                                    size,
5845                                    i.codecId);
5846
5847            if (status)
5848                return status;
5849        }
5850        else if (id == 0x1C)  //lacing
5851        {
5852            lacing = UnserializeUInt(pReader, pos, size);
5853
5854            if ((lacing < 0) || (lacing > 1))
5855                return E_FILE_FORMAT_INVALID;
5856        }
5857        else if (id == 0x23A2)  //Codec Private
5858        {
5859            delete[] i.codecPrivate;
5860            i.codecPrivate = NULL;
5861            i.codecPrivateSize = 0;
5862
5863            if (size <= 0)
5864                return E_FILE_FORMAT_INVALID;
5865
5866            const size_t buflen = static_cast<size_t>(size);
5867
5868            typedef unsigned char* buf_t;
5869
5870            const buf_t buf = new (std::nothrow) unsigned char[buflen];
5871
5872            if (buf == NULL)
5873                return -1;
5874
5875            const int status = pReader->Read(pos, buflen, buf);
5876
5877            if (status)
5878            {
5879                delete[] buf;
5880                return status;
5881            }
5882
5883            i.codecPrivate = buf;
5884            i.codecPrivateSize = buflen;
5885        }
5886        else if (id == 0x058688)  //Codec Name
5887        {
5888            const long status = UnserializeString(
5889                                    pReader,
5890                                    pos,
5891                                    size,
5892                                    i.codecNameAsUTF8);
5893
5894            if (status)
5895                return status;
5896        }
5897
5898        pos += size;  //consume payload
5899        assert(pos <= track_stop);
5900    }
5901
5902    assert(pos == track_stop);
5903
5904    if (i.number <= 0)  //not specified
5905        return E_FILE_FORMAT_INVALID;
5906
5907    if (GetTrackByNumber(i.number))
5908        return E_FILE_FORMAT_INVALID;
5909
5910    if (i.type <= 0)  //not specified
5911        return E_FILE_FORMAT_INVALID;
5912
5913    if ((i.type != Track::kVideo) && (i.type != Track::kAudio))
5914    {
5915        //TODO(matthewjheaney): go ahead and create a "generic" track
5916        //object, so that GetTrackByXXX always returns something, even
5917        //if the object it returns has a type that is not kVideo or kAudio.
5918
5919        return 0;  //no error
5920    }
5921
5922    i.lacing = (lacing > 0) ? true : false;
5923
5924    long status;
5925
5926    if (i.type == Track::kVideo)
5927    {
5928        if (v.start < 0)
5929            return E_FILE_FORMAT_INVALID;
5930
5931        if (a.start >= 0)
5932            return E_FILE_FORMAT_INVALID;
5933
5934        i.settings = v;
5935
5936        VideoTrack* p = NULL;
5937
5938        status = VideoTrack::Parse(m_pSegment, i, elem_st, elem_sz, p);
5939        pTrack = p;
5940    }
5941    else
5942    {
5943        assert(i.type == Track::kAudio);
5944
5945        if (a.start < 0)
5946            return E_FILE_FORMAT_INVALID;
5947
5948        if (v.start >= 0)
5949            return E_FILE_FORMAT_INVALID;
5950
5951        i.settings = a;
5952
5953        AudioTrack* p = NULL;
5954
5955        status = AudioTrack::Parse(m_pSegment, i, elem_st, elem_sz, p);
5956        pTrack = p;
5957    }
5958
5959    if (status)
5960        return status;
5961
5962    assert(pTrack);
5963
5964    if (e.start >= 0)
5965        pTrack->ParseContentEncodingsEntry(e.start, e.size);
5966
5967    return 0;  //success
5968}
5969
5970
5971Tracks::~Tracks()
5972{
5973    Track** i = m_trackEntries;
5974    Track** const j = m_trackEntriesEnd;
5975
5976    while (i != j)
5977    {
5978        Track* const pTrack = *i++;
5979        delete pTrack;
5980    }
5981
5982    delete[] m_trackEntries;
5983}
5984
5985const Track* Tracks::GetTrackByNumber(long tn) const
5986{
5987    if (tn < 0)
5988        return NULL;
5989
5990    Track** i = m_trackEntries;
5991    Track** const j = m_trackEntriesEnd;
5992
5993    while (i != j)
5994    {
5995        Track* const pTrack = *i++;
5996
5997        if (pTrack == NULL)
5998            continue;
5999
6000        if (tn == pTrack->GetNumber())
6001            return pTrack;
6002    }
6003
6004    return NULL;  //not found
6005}
6006
6007
6008const Track* Tracks::GetTrackByIndex(unsigned long idx) const
6009{
6010    const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
6011
6012    if (idx >= static_cast<unsigned long>(count))
6013         return NULL;
6014
6015    return m_trackEntries[idx];
6016}
6017
6018#if 0
6019long long Cluster::Unparsed() const
6020{
6021    if (m_timecode < 0)  //not even partially loaded
6022        return LLONG_MAX;
6023
6024    assert(m_pos >= m_element_start);
6025    //assert(m_element_size > m_size);
6026
6027    const long long element_stop = m_element_start + m_element_size;
6028    assert(m_pos <= element_stop);
6029
6030    const long long result = element_stop - m_pos;
6031    assert(result >= 0);
6032
6033    return result;
6034}
6035#endif
6036
6037
6038long Cluster::Load(long long& pos, long& len) const
6039{
6040    assert(m_pSegment);
6041    assert(m_pos >= m_element_start);
6042
6043    if (m_timecode >= 0)  //at least partially loaded
6044        return 0;
6045
6046    assert(m_pos == m_element_start);
6047    assert(m_element_size < 0);
6048
6049    IMkvReader* const pReader = m_pSegment->m_pReader;
6050
6051    long long total, avail;
6052
6053    const int status = pReader->Length(&total, &avail);
6054
6055    if (status < 0)  //error
6056        return status;
6057
6058    assert((total < 0) || (avail <= total));
6059    assert((total < 0) || (m_pos <= total));  //TODO: verify this
6060
6061    pos = m_pos;
6062
6063    long long cluster_size = -1;
6064
6065    {
6066        if ((pos + 1) > avail)
6067        {
6068            len = 1;
6069            return E_BUFFER_NOT_FULL;
6070        }
6071
6072        long long result = GetUIntLength(pReader, pos, len);
6073
6074        if (result < 0)  //error or underflow
6075            return static_cast<long>(result);
6076
6077        if (result > 0)  //underflow (weird)
6078            return E_BUFFER_NOT_FULL;
6079
6080        //if ((pos + len) > segment_stop)
6081        //    return E_FILE_FORMAT_INVALID;
6082
6083        if ((pos + len) > avail)
6084            return E_BUFFER_NOT_FULL;
6085
6086        const long long id_ = ReadUInt(pReader, pos, len);
6087
6088        if (id_ < 0)  //error
6089            return static_cast<long>(id_);
6090
6091        if (id_ != 0x0F43B675)  //Cluster ID
6092            return E_FILE_FORMAT_INVALID;
6093
6094        pos += len;  //consume id
6095
6096        //read cluster size
6097
6098        if ((pos + 1) > avail)
6099        {
6100            len = 1;
6101            return E_BUFFER_NOT_FULL;
6102        }
6103
6104        result = GetUIntLength(pReader, pos, len);
6105
6106        if (result < 0)  //error
6107            return static_cast<long>(result);
6108
6109        if (result > 0)  //weird
6110            return E_BUFFER_NOT_FULL;
6111
6112        //if ((pos + len) > segment_stop)
6113        //    return E_FILE_FORMAT_INVALID;
6114
6115        if ((pos + len) > avail)
6116            return E_BUFFER_NOT_FULL;
6117
6118        const long long size = ReadUInt(pReader, pos, len);
6119
6120        if (size < 0)  //error
6121            return static_cast<long>(cluster_size);
6122
6123        if (size == 0)
6124            return E_FILE_FORMAT_INVALID;  //TODO: verify this
6125
6126        pos += len;  //consume length of size of element
6127
6128        const long long unknown_size = (1LL << (7 * len)) - 1;
6129
6130        if (size != unknown_size)
6131            cluster_size = size;
6132    }
6133
6134    //pos points to start of payload
6135
6136#if 0
6137    len = static_cast<long>(size_);
6138
6139    if (cluster_stop > avail)
6140        return E_BUFFER_NOT_FULL;
6141#endif
6142
6143    long long timecode = -1;
6144    long long new_pos = -1;
6145    bool bBlock = false;
6146
6147    long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
6148
6149    for (;;)
6150    {
6151        if ((cluster_stop >= 0) && (pos >= cluster_stop))
6152            break;
6153
6154        //Parse ID
6155
6156        if ((pos + 1) > avail)
6157        {
6158            len = 1;
6159            return E_BUFFER_NOT_FULL;
6160        }
6161
6162        long long result = GetUIntLength(pReader, pos, len);
6163
6164        if (result < 0)  //error
6165            return static_cast<long>(result);
6166
6167        if (result > 0)  //weird
6168            return E_BUFFER_NOT_FULL;
6169
6170        if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6171            return E_FILE_FORMAT_INVALID;
6172
6173        if ((pos + len) > avail)
6174            return E_BUFFER_NOT_FULL;
6175
6176        const long long id = ReadUInt(pReader, pos, len);
6177
6178        if (id < 0) //error
6179            return static_cast<long>(id);
6180
6181        if (id == 0)
6182            return E_FILE_FORMAT_INVALID;
6183
6184        //This is the distinguished set of ID's we use to determine
6185        //that we have exhausted the sub-element's inside the cluster
6186        //whose ID we parsed earlier.
6187
6188        if (id == 0x0F43B675)  //Cluster ID
6189            break;
6190
6191        if (id == 0x0C53BB6B)  //Cues ID
6192            break;
6193
6194        pos += len;  //consume ID field
6195
6196        //Parse Size
6197
6198        if ((pos + 1) > avail)
6199        {
6200            len = 1;
6201            return E_BUFFER_NOT_FULL;
6202        }
6203
6204        result = GetUIntLength(pReader, pos, len);
6205
6206        if (result < 0)  //error
6207            return static_cast<long>(result);
6208
6209        if (result > 0)  //weird
6210            return E_BUFFER_NOT_FULL;
6211
6212        if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6213            return E_FILE_FORMAT_INVALID;
6214
6215        if ((pos + len) > avail)
6216            return E_BUFFER_NOT_FULL;
6217
6218        const long long size = ReadUInt(pReader, pos, len);
6219
6220        if (size < 0)  //error
6221            return static_cast<long>(size);
6222
6223        const long long unknown_size = (1LL << (7 * len)) - 1;
6224
6225        if (size == unknown_size)
6226            return E_FILE_FORMAT_INVALID;
6227
6228        pos += len;  //consume size field
6229
6230        if ((cluster_stop >= 0) && (pos > cluster_stop))
6231            return E_FILE_FORMAT_INVALID;
6232
6233        //pos now points to start of payload
6234
6235        if (size == 0)  //weird
6236            continue;
6237
6238        if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
6239            return E_FILE_FORMAT_INVALID;
6240
6241        if (id == 0x67)  //TimeCode ID
6242        {
6243            len = static_cast<long>(size);
6244
6245            if ((pos + size) > avail)
6246                return E_BUFFER_NOT_FULL;
6247
6248            timecode = UnserializeUInt(pReader, pos, size);
6249
6250            if (timecode < 0)  //error (or underflow)
6251                return static_cast<long>(timecode);
6252
6253            new_pos = pos + size;
6254
6255            if (bBlock)
6256                break;
6257        }
6258        else if (id == 0x20)  //BlockGroup ID
6259        {
6260            bBlock = true;
6261            break;
6262        }
6263        else if (id == 0x23)  //SimpleBlock ID
6264        {
6265            bBlock = true;
6266            break;
6267        }
6268
6269        pos += size;  //consume payload
6270        assert((cluster_stop < 0) || (pos <= cluster_stop));
6271    }
6272
6273    assert((cluster_stop < 0) || (pos <= cluster_stop));
6274
6275    if (timecode < 0)  //no timecode found
6276        return E_FILE_FORMAT_INVALID;
6277
6278    if (!bBlock)
6279        return E_FILE_FORMAT_INVALID;
6280
6281    m_pos = new_pos;  //designates position just beyond timecode payload
6282    m_timecode = timecode;  // m_timecode >= 0 means we're partially loaded
6283
6284    if (cluster_size >= 0)
6285        m_element_size = cluster_stop - m_element_start;
6286
6287    return 0;
6288}
6289
6290
6291long Cluster::Parse(long long& pos, long& len) const
6292{
6293    long status = Load(pos, len);
6294
6295    if (status < 0)
6296        return status;
6297
6298    assert(m_pos >= m_element_start);
6299    assert(m_timecode >= 0);
6300    //assert(m_size > 0);
6301    //assert(m_element_size > m_size);
6302
6303    const long long cluster_stop =
6304        (m_element_size < 0) ? -1 : m_element_start + m_element_size;
6305
6306    if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
6307        return 1;  //nothing else to do
6308
6309    IMkvReader* const pReader = m_pSegment->m_pReader;
6310
6311    long long total, avail;
6312
6313    status = pReader->Length(&total, &avail);
6314
6315    if (status < 0)  //error
6316        return status;
6317
6318    assert((total < 0) || (avail <= total));
6319
6320    pos = m_pos;
6321
6322    for (;;)
6323    {
6324        if ((cluster_stop >= 0) && (pos >= cluster_stop))
6325            break;
6326
6327        if ((total >= 0) && (pos >= total))
6328        {
6329            if (m_element_size < 0)
6330                m_element_size = pos - m_element_start;
6331
6332            break;
6333        }
6334
6335        //Parse ID
6336
6337        if ((pos + 1) > avail)
6338        {
6339            len = 1;
6340            return E_BUFFER_NOT_FULL;
6341        }
6342
6343        long long result = GetUIntLength(pReader, pos, len);
6344
6345        if (result < 0)  //error
6346            return static_cast<long>(result);
6347
6348        if (result > 0)  //weird
6349            return E_BUFFER_NOT_FULL;
6350
6351        if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6352            return E_FILE_FORMAT_INVALID;
6353
6354        if ((pos + len) > avail)
6355            return E_BUFFER_NOT_FULL;
6356
6357        const long long id = ReadUInt(pReader, pos, len);
6358
6359        if (id < 0) //error
6360            return static_cast<long>(id);
6361
6362        if (id == 0)  //weird
6363            return E_FILE_FORMAT_INVALID;
6364
6365        //This is the distinguished set of ID's we use to determine
6366        //that we have exhausted the sub-element's inside the cluster
6367        //whose ID we parsed earlier.
6368
6369        if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) //Cluster or Cues ID
6370        {
6371            if (m_element_size < 0)
6372                m_element_size = pos - m_element_start;
6373
6374            break;
6375        }
6376
6377        pos += len;  //consume ID field
6378
6379        //Parse Size
6380
6381        if ((pos + 1) > avail)
6382        {
6383            len = 1;
6384            return E_BUFFER_NOT_FULL;
6385        }
6386
6387        result = GetUIntLength(pReader, pos, len);
6388
6389        if (result < 0)  //error
6390            return static_cast<long>(result);
6391
6392        if (result > 0)  //weird
6393            return E_BUFFER_NOT_FULL;
6394
6395        if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6396            return E_FILE_FORMAT_INVALID;
6397
6398        if ((pos + len) > avail)
6399            return E_BUFFER_NOT_FULL;
6400
6401        const long long size = ReadUInt(pReader, pos, len);
6402
6403        if (size < 0)  //error
6404            return static_cast<long>(size);
6405
6406        const long long unknown_size = (1LL << (7 * len)) - 1;
6407
6408        if (size == unknown_size)
6409            return E_FILE_FORMAT_INVALID;
6410
6411        pos += len;  //consume size field
6412
6413        if ((cluster_stop >= 0) && (pos > cluster_stop))
6414            return E_FILE_FORMAT_INVALID;
6415
6416        //pos now points to start of payload
6417
6418        if (size == 0)  //weird
6419            continue;
6420
6421        //const long long block_start = pos;
6422        const long long block_stop = pos + size;
6423
6424        if (cluster_stop >= 0)
6425        {
6426            if (block_stop > cluster_stop)
6427                return E_FILE_FORMAT_INVALID;
6428        }
6429        else if ((total >= 0) && (block_stop > total))
6430        {
6431            m_element_size = total - m_element_start;
6432            pos = total;
6433            break;
6434        }
6435        else if (block_stop > avail)
6436        {
6437            len = static_cast<long>(size);
6438            return E_BUFFER_NOT_FULL;
6439        }
6440
6441        Cluster* const this_ = const_cast<Cluster*>(this);
6442
6443        if (id == 0x20)  //BlockGroup
6444            return this_->ParseBlockGroup(size, pos, len);
6445
6446        if (id == 0x23)  //SimpleBlock
6447            return this_->ParseSimpleBlock(size, pos, len);
6448
6449        pos += size;  //consume payload
6450        assert((cluster_stop < 0) || (pos <= cluster_stop));
6451    }
6452
6453    assert(m_element_size > 0);
6454
6455    m_pos = pos;
6456    assert((cluster_stop < 0) || (m_pos <= cluster_stop));
6457
6458    if (m_entries_count > 0)
6459    {
6460        const long idx = m_entries_count - 1;
6461
6462        const BlockEntry* const pLast = m_entries[idx];
6463        assert(pLast);
6464
6465        const Block* const pBlock = pLast->GetBlock();
6466        assert(pBlock);
6467
6468        const long long start = pBlock->m_start;
6469
6470        if ((total >= 0) && (start > total))
6471            return -1;  //defend against trucated stream
6472
6473        const long long size = pBlock->m_size;
6474
6475        const long long stop = start + size;
6476        assert((cluster_stop < 0) || (stop <= cluster_stop));
6477
6478        if ((total >= 0) && (stop > total))
6479            return -1;  //defend against trucated stream
6480    }
6481
6482    return 1;  //no more entries
6483}
6484
6485
6486long Cluster::ParseSimpleBlock(
6487    long long block_size,
6488    long long& pos,
6489    long& len)
6490{
6491    const long long block_start = pos;
6492    const long long block_stop = pos + block_size;
6493
6494    IMkvReader* const pReader = m_pSegment->m_pReader;
6495
6496    long long total, avail;
6497
6498    long status = pReader->Length(&total, &avail);
6499
6500    if (status < 0)  //error
6501        return status;
6502
6503    assert((total < 0) || (avail <= total));
6504
6505    //parse track number
6506
6507    if ((pos + 1) > avail)
6508    {
6509        len = 1;
6510        return E_BUFFER_NOT_FULL;
6511    }
6512
6513    long long result = GetUIntLength(pReader, pos, len);
6514
6515    if (result < 0)  //error
6516        return static_cast<long>(result);
6517
6518    if (result > 0)  //weird
6519        return E_BUFFER_NOT_FULL;
6520
6521    if ((pos + len) > block_stop)
6522        return E_FILE_FORMAT_INVALID;
6523
6524    if ((pos + len) > avail)
6525        return E_BUFFER_NOT_FULL;
6526
6527    const long long track = ReadUInt(pReader, pos, len);
6528
6529    if (track < 0) //error
6530        return static_cast<long>(track);
6531
6532    if (track == 0)
6533        return E_FILE_FORMAT_INVALID;
6534
6535#if 0
6536    //TODO(matthewjheaney)
6537    //This turned out to be too conservative.  The problem is that
6538    //if we see a track header in the tracks element with an unsupported
6539    //track type, we throw that track header away, so it is not present
6540    //in the track map.  But even though we don't understand the track
6541    //header, there are still blocks in the cluster with that track
6542    //number.  It was our decision to ignore that track header, so it's
6543    //up to us to deal with blocks associated with that track -- we
6544    //cannot simply report an error since technically there's nothing
6545    //wrong with the file.
6546    //
6547    //For now we go ahead and finish the parse, creating a block entry
6548    //for this block.  This is somewhat wasteful, because without a
6549    //track header there's nothing you can do with the block. What
6550    //we really need here is a special return value that indicates to
6551    //the caller that he should ignore this particular block, and
6552    //continue parsing.
6553
6554    const Tracks* const pTracks = m_pSegment->GetTracks();
6555    assert(pTracks);
6556
6557    const long tn = static_cast<long>(track);
6558
6559    const Track* const pTrack = pTracks->GetTrackByNumber(tn);
6560
6561    if (pTrack == NULL)
6562        return E_FILE_FORMAT_INVALID;
6563#endif
6564
6565    pos += len;  //consume track number
6566
6567    if ((pos + 2) > block_stop)
6568        return E_FILE_FORMAT_INVALID;
6569
6570    if ((pos + 2) > avail)
6571    {
6572        len = 2;
6573        return E_BUFFER_NOT_FULL;
6574    }
6575
6576    pos += 2;  //consume timecode
6577
6578    if ((pos + 1) > block_stop)
6579        return E_FILE_FORMAT_INVALID;
6580
6581    if ((pos + 1) > avail)
6582    {
6583        len = 1;
6584        return E_BUFFER_NOT_FULL;
6585    }
6586
6587    unsigned char flags;
6588
6589    status = pReader->Read(pos, 1, &flags);
6590
6591    if (status < 0)  //error or underflow
6592    {
6593        len = 1;
6594        return status;
6595    }
6596
6597    ++pos;  //consume flags byte
6598    assert(pos <= avail);
6599
6600    if (pos >= block_stop)
6601        return E_FILE_FORMAT_INVALID;
6602
6603    const int lacing = int(flags & 0x06) >> 1;
6604
6605    if ((lacing != 0) && (block_stop > avail))
6606    {
6607        len = static_cast<long>(block_stop - pos);
6608        return E_BUFFER_NOT_FULL;
6609    }
6610
6611    status = CreateBlock(0x23, block_start, block_size);  //simple block id
6612
6613    if (status != 0)
6614        return status;
6615
6616    m_pos = block_stop;
6617
6618    return 0;  //success
6619}
6620
6621
6622long Cluster::ParseBlockGroup(
6623    long long payload_size,
6624    long long& pos,
6625    long& len)
6626{
6627    const long long payload_start = pos;
6628    const long long payload_stop = pos + payload_size;
6629
6630    IMkvReader* const pReader = m_pSegment->m_pReader;
6631
6632    long long total, avail;
6633
6634    long status = pReader->Length(&total, &avail);
6635
6636    if (status < 0)  //error
6637        return status;
6638
6639    assert((total < 0) || (avail <= total));
6640
6641    if ((total >= 0) && (payload_stop > total))
6642        return E_FILE_FORMAT_INVALID;
6643
6644    if (payload_stop > avail)
6645    {
6646         len = static_cast<long>(payload_size);
6647         return E_BUFFER_NOT_FULL;
6648    }
6649
6650    while (pos < payload_stop)
6651    {
6652        //parse sub-block element ID
6653
6654        if ((pos + 1) > avail)
6655        {
6656            len = 1;
6657            return E_BUFFER_NOT_FULL;
6658        }
6659
6660        long long result = GetUIntLength(pReader, pos, len);
6661
6662        if (result < 0)  //error
6663            return static_cast<long>(result);
6664
6665        if (result > 0)  //weird
6666            return E_BUFFER_NOT_FULL;
6667
6668        if ((pos + len) > payload_stop)
6669            return E_FILE_FORMAT_INVALID;
6670
6671        if ((pos + len) > avail)
6672            return E_BUFFER_NOT_FULL;
6673
6674        const long long id = ReadUInt(pReader, pos, len);
6675
6676        if (id < 0) //error
6677            return static_cast<long>(id);
6678
6679        if (id == 0)  //not a value ID
6680            return E_FILE_FORMAT_INVALID;
6681
6682        pos += len;  //consume ID field
6683
6684        //Parse Size
6685
6686        if ((pos + 1) > avail)
6687        {
6688            len = 1;
6689            return E_BUFFER_NOT_FULL;
6690        }
6691
6692        result = GetUIntLength(pReader, pos, len);
6693
6694        if (result < 0)  //error
6695            return static_cast<long>(result);
6696
6697        if (result > 0)  //weird
6698            return E_BUFFER_NOT_FULL;
6699
6700        if ((pos + len) > payload_stop)
6701            return E_FILE_FORMAT_INVALID;
6702
6703        if ((pos + len) > avail)
6704            return E_BUFFER_NOT_FULL;
6705
6706        const long long size = ReadUInt(pReader, pos, len);
6707
6708        if (size < 0)  //error
6709            return static_cast<long>(size);
6710
6711        pos += len;  //consume size field
6712
6713        //pos now points to start of sub-block group payload
6714
6715        if (pos > payload_stop)
6716            return E_FILE_FORMAT_INVALID;
6717
6718        if (size == 0)  //weird
6719            continue;
6720
6721        const long long unknown_size = (1LL << (7 * len)) - 1;
6722
6723        if (size == unknown_size)
6724            return E_FILE_FORMAT_INVALID;
6725
6726        if (id != 0x21)  //sub-part of BlockGroup is not a Block
6727        {
6728            pos += size;  //consume sub-part of block group
6729
6730            if (pos > payload_stop)
6731                return E_FILE_FORMAT_INVALID;
6732
6733            continue;
6734        }
6735
6736        const long long block_stop = pos + size;
6737
6738        if (block_stop > payload_stop)
6739            return E_FILE_FORMAT_INVALID;
6740
6741        //parse track number
6742
6743        if ((pos + 1) > avail)
6744        {
6745            len = 1;
6746            return E_BUFFER_NOT_FULL;
6747        }
6748
6749        result = GetUIntLength(pReader, pos, len);
6750
6751        if (result < 0)  //error
6752            return static_cast<long>(result);
6753
6754        if (result > 0)  //weird
6755            return E_BUFFER_NOT_FULL;
6756
6757        if ((pos + len) > block_stop)
6758            return E_FILE_FORMAT_INVALID;
6759
6760        if ((pos + len) > avail)
6761            return E_BUFFER_NOT_FULL;
6762
6763        const long long track = ReadUInt(pReader, pos, len);
6764
6765        if (track < 0) //error
6766            return static_cast<long>(track);
6767
6768        if (track == 0)
6769            return E_FILE_FORMAT_INVALID;
6770
6771#if 0
6772        //TODO(matthewjheaney)
6773        //This turned out to be too conservative.  The problem is that
6774        //if we see a track header in the tracks element with an unsupported
6775        //track type, we throw that track header away, so it is not present
6776        //in the track map.  But even though we don't understand the track
6777        //header, there are still blocks in the cluster with that track
6778        //number.  It was our decision to ignore that track header, so it's
6779        //up to us to deal with blocks associated with that track -- we
6780        //cannot simply report an error since technically there's nothing
6781        //wrong with the file.
6782        //
6783        //For now we go ahead and finish the parse, creating a block entry
6784        //for this block.  This is somewhat wasteful, because without a
6785        //track header there's nothing you can do with the block. What
6786        //we really need here is a special return value that indicates to
6787        //the caller that he should ignore this particular block, and
6788        //continue parsing.
6789
6790        const Tracks* const pTracks = m_pSegment->GetTracks();
6791        assert(pTracks);
6792
6793        const long tn = static_cast<long>(track);
6794
6795        const Track* const pTrack = pTracks->GetTrackByNumber(tn);
6796
6797        if (pTrack == NULL)
6798            return E_FILE_FORMAT_INVALID;
6799#endif
6800
6801        pos += len;  //consume track number
6802
6803        if ((pos + 2) > block_stop)
6804            return E_FILE_FORMAT_INVALID;
6805
6806        if ((pos + 2) > avail)
6807        {
6808            len = 2;
6809            return E_BUFFER_NOT_FULL;
6810        }
6811
6812        pos += 2;  //consume timecode
6813
6814        if ((pos + 1) > block_stop)
6815            return E_FILE_FORMAT_INVALID;
6816
6817        if ((pos + 1) > avail)
6818        {
6819            len = 1;
6820            return E_BUFFER_NOT_FULL;
6821        }
6822
6823        unsigned char flags;
6824
6825        status = pReader->Read(pos, 1, &flags);
6826
6827        if (status < 0)  //error or underflow
6828        {
6829            len = 1;
6830            return status;
6831        }
6832
6833        ++pos;  //consume flags byte
6834        assert(pos <= avail);
6835
6836        if (pos >= block_stop)
6837            return E_FILE_FORMAT_INVALID;
6838
6839        const int lacing = int(flags & 0x06) >> 1;
6840
6841        if ((lacing != 0) && (block_stop > avail))
6842        {
6843            len = static_cast<long>(block_stop - pos);
6844            return E_BUFFER_NOT_FULL;
6845        }
6846
6847        pos = block_stop;  //consume block-part of block group
6848        assert(pos <= payload_stop);
6849    }
6850
6851    assert(pos == payload_stop);
6852
6853    status = CreateBlock(0x20, payload_start, payload_size);  //BlockGroup ID
6854
6855    if (status != 0)
6856        return status;
6857
6858    m_pos = payload_stop;
6859
6860    return 0;  //success
6861}
6862
6863
6864long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const
6865{
6866    assert(m_pos >= m_element_start);
6867
6868    pEntry = NULL;
6869
6870    if (index < 0)
6871        return -1;  //generic error
6872
6873    if (m_entries_count < 0)
6874        return E_BUFFER_NOT_FULL;
6875
6876    assert(m_entries);
6877    assert(m_entries_size > 0);
6878    assert(m_entries_count <= m_entries_size);
6879
6880    if (index < m_entries_count)
6881    {
6882        pEntry = m_entries[index];
6883        assert(pEntry);
6884
6885        return 1;  //found entry
6886    }
6887
6888    if (m_element_size < 0)        //we don't know cluster end yet
6889        return E_BUFFER_NOT_FULL;  //underflow
6890
6891    const long long element_stop = m_element_start + m_element_size;
6892
6893    if (m_pos >= element_stop)
6894        return 0;  //nothing left to parse
6895
6896    return E_BUFFER_NOT_FULL;  //underflow, since more remains to be parsed
6897}
6898
6899
6900Cluster* Cluster::Create(
6901    Segment* pSegment,
6902    long idx,
6903    long long off)
6904    //long long element_size)
6905{
6906    assert(pSegment);
6907    assert(off >= 0);
6908
6909    const long long element_start = pSegment->m_start + off;
6910
6911    Cluster* const pCluster = new Cluster(pSegment,
6912                                          idx,
6913                                          element_start);
6914                                          //element_size);
6915    assert(pCluster);
6916
6917    return pCluster;
6918}
6919
6920
6921Cluster::Cluster() :
6922    m_pSegment(NULL),
6923    m_element_start(0),
6924    m_index(0),
6925    m_pos(0),
6926    m_element_size(0),
6927    m_timecode(0),
6928    m_entries(NULL),
6929    m_entries_size(0),
6930    m_entries_count(0)  //means "no entries"
6931{
6932}
6933
6934
6935Cluster::Cluster(
6936    Segment* pSegment,
6937    long idx,
6938    long long element_start
6939    /* long long element_size */ ) :
6940    m_pSegment(pSegment),
6941    m_element_start(element_start),
6942    m_index(idx),
6943    m_pos(element_start),
6944    m_element_size(-1 /* element_size */ ),
6945    m_timecode(-1),
6946    m_entries(NULL),
6947    m_entries_size(0),
6948    m_entries_count(-1)  //means "has not been parsed yet"
6949{
6950}
6951
6952
6953Cluster::~Cluster()
6954{
6955    if (m_entries_count <= 0)
6956        return;
6957
6958    BlockEntry** i = m_entries;
6959    BlockEntry** const j = m_entries + m_entries_count;
6960
6961    while (i != j)
6962    {
6963         BlockEntry* p = *i++;
6964         assert(p);
6965
6966         delete p;
6967    }
6968
6969    delete[] m_entries;
6970}
6971
6972
6973bool Cluster::EOS() const
6974{
6975    return (m_pSegment == NULL);
6976}
6977
6978
6979long Cluster::GetIndex() const
6980{
6981    return m_index;
6982}
6983
6984
6985long long Cluster::GetPosition() const
6986{
6987    const long long pos = m_element_start - m_pSegment->m_start;
6988    assert(pos >= 0);
6989
6990    return pos;
6991}
6992
6993
6994long long Cluster::GetElementSize() const
6995{
6996    return m_element_size;
6997}
6998
6999
7000#if 0
7001bool Cluster::HasBlockEntries(
7002    const Segment* pSegment,
7003    long long off)  //relative to start of segment payload
7004{
7005    assert(pSegment);
7006    assert(off >= 0);  //relative to segment
7007
7008    IMkvReader* const pReader = pSegment->m_pReader;
7009
7010    long long pos = pSegment->m_start + off;  //absolute
7011    long long size;
7012
7013    {
7014        long len;
7015
7016        const long long id = ReadUInt(pReader, pos, len);
7017        (void)id;
7018        assert(id >= 0);
7019        assert(id == 0x0F43B675);  //Cluster ID
7020
7021        pos += len;  //consume id
7022
7023        size = ReadUInt(pReader, pos, len);
7024        assert(size > 0);
7025
7026        pos += len;  //consume size
7027
7028        //pos now points to start of payload
7029    }
7030
7031    const long long stop = pos + size;
7032
7033    while (pos < stop)
7034    {
7035        long len;
7036
7037        const long long id = ReadUInt(pReader, pos, len);
7038        assert(id >= 0);  //TODO
7039        assert((pos + len) <= stop);
7040
7041        pos += len;  //consume id
7042
7043        const long long size = ReadUInt(pReader, pos, len);
7044        assert(size >= 0);  //TODO
7045        assert((pos + len) <= stop);
7046
7047        pos += len;  //consume size
7048
7049        if (id == 0x20)  //BlockGroup ID
7050            return true;
7051
7052        if (id == 0x23)  //SimpleBlock ID
7053            return true;
7054
7055        pos += size;  //consume payload
7056        assert(pos <= stop);
7057    }
7058
7059    return false;
7060}
7061#endif
7062
7063
7064long Cluster::HasBlockEntries(
7065    const Segment* pSegment,
7066    long long off,  //relative to start of segment payload
7067    long long& pos,
7068    long& len)
7069{
7070    assert(pSegment);
7071    assert(off >= 0);  //relative to segment
7072
7073    IMkvReader* const pReader = pSegment->m_pReader;
7074
7075    long long total, avail;
7076
7077    long status = pReader->Length(&total, &avail);
7078
7079    if (status < 0)  //error
7080        return status;
7081
7082    assert((total < 0) || (avail <= total));
7083
7084    pos = pSegment->m_start + off;  //absolute
7085
7086    if ((total >= 0) && (pos >= total))
7087        return 0;  //we don't even have a complete cluster
7088
7089    const long long segment_stop =
7090        (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
7091
7092    long long cluster_stop = -1;  //interpreted later to mean "unknown size"
7093
7094    {
7095        if ((pos + 1) > avail)
7096        {
7097            len = 1;
7098            return E_BUFFER_NOT_FULL;
7099        }
7100
7101        long long result = GetUIntLength(pReader, pos, len);
7102
7103        if (result < 0)  //error
7104            return static_cast<long>(result);
7105
7106        if (result > 0)  //need more data
7107            return E_BUFFER_NOT_FULL;
7108
7109        if ((segment_stop >= 0) && ((pos + len) > segment_stop))
7110            return E_FILE_FORMAT_INVALID;
7111
7112        if ((total >= 0) && ((pos + len) > total))
7113            return 0;
7114
7115        if ((pos + len) > avail)
7116            return E_BUFFER_NOT_FULL;
7117
7118        const long long id = ReadUInt(pReader, pos, len);
7119
7120        if (id < 0)  //error
7121            return static_cast<long>(id);
7122
7123        if (id != 0x0F43B675)  //weird: not cluster ID
7124            return -1;         //generic error
7125
7126        pos += len;  //consume Cluster ID field
7127
7128        //read size field
7129
7130        if ((pos + 1) > avail)
7131        {
7132            len = 1;
7133            return E_BUFFER_NOT_FULL;
7134        }
7135
7136        result = GetUIntLength(pReader, pos, len);
7137
7138        if (result < 0)  //error
7139            return static_cast<long>(result);
7140
7141        if (result > 0)  //weird
7142            return E_BUFFER_NOT_FULL;
7143
7144        if ((segment_stop >= 0) && ((pos + len) > segment_stop))
7145            return E_FILE_FORMAT_INVALID;
7146
7147        if ((total >= 0) && ((pos + len) > total))
7148            return 0;
7149
7150        if ((pos + len) > avail)
7151            return E_BUFFER_NOT_FULL;
7152
7153        const long long size = ReadUInt(pReader, pos, len);
7154
7155        if (size < 0)  //error
7156            return static_cast<long>(size);
7157
7158        if (size == 0)
7159            return 0;  //cluster does not have entries
7160
7161        pos += len;  //consume size field
7162
7163        //pos now points to start of payload
7164
7165        const long long unknown_size = (1LL << (7 * len)) - 1;
7166
7167        if (size != unknown_size)
7168        {
7169            cluster_stop = pos + size;
7170            assert(cluster_stop >= 0);
7171
7172            if ((segment_stop >= 0) && (cluster_stop > segment_stop))
7173                return E_FILE_FORMAT_INVALID;
7174
7175            if ((total >= 0) && (cluster_stop > total))
7176                //return E_FILE_FORMAT_INVALID;  //too conservative
7177                return 0;  //cluster does not have any entries
7178        }
7179    }
7180
7181    for (;;)
7182    {
7183        if ((cluster_stop >= 0) && (pos >= cluster_stop))
7184            return 0;  //no entries detected
7185
7186        if ((pos + 1) > avail)
7187        {
7188            len = 1;
7189            return E_BUFFER_NOT_FULL;
7190        }
7191
7192        long long result = GetUIntLength(pReader, pos, len);
7193
7194        if (result < 0)  //error
7195            return static_cast<long>(result);
7196
7197        if (result > 0)  //need more data
7198            return E_BUFFER_NOT_FULL;
7199
7200        if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7201            return E_FILE_FORMAT_INVALID;
7202
7203        if ((pos + len) > avail)
7204            return E_BUFFER_NOT_FULL;
7205
7206        const long long id = ReadUInt(pReader, pos, len);
7207
7208        if (id < 0)  //error
7209            return static_cast<long>(id);
7210
7211        //This is the distinguished set of ID's we use to determine
7212        //that we have exhausted the sub-element's inside the cluster
7213        //whose ID we parsed earlier.
7214
7215        if (id == 0x0F43B675)  //Cluster ID
7216            return 0;  //no entries found
7217
7218        if (id == 0x0C53BB6B)  //Cues ID
7219            return 0;  //no entries found
7220
7221        pos += len;  //consume id field
7222
7223        if ((cluster_stop >= 0) && (pos >= cluster_stop))
7224            return E_FILE_FORMAT_INVALID;
7225
7226        //read size field
7227
7228        if ((pos + 1) > avail)
7229        {
7230            len = 1;
7231            return E_BUFFER_NOT_FULL;
7232        }
7233
7234        result = GetUIntLength(pReader, pos, len);
7235
7236        if (result < 0)  //error
7237            return static_cast<long>(result);
7238
7239        if (result > 0)  //underflow
7240            return E_BUFFER_NOT_FULL;
7241
7242        if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7243            return E_FILE_FORMAT_INVALID;
7244
7245        if ((pos + len) > avail)
7246            return E_BUFFER_NOT_FULL;
7247
7248        const long long size = ReadUInt(pReader, pos, len);
7249
7250        if (size < 0)  //error
7251            return static_cast<long>(size);
7252
7253        pos += len;  //consume size field
7254
7255        //pos now points to start of payload
7256
7257        if ((cluster_stop >= 0) && (pos > cluster_stop))
7258            return E_FILE_FORMAT_INVALID;
7259
7260        if (size == 0)  //weird
7261            continue;
7262
7263        const long long unknown_size = (1LL << (7 * len)) - 1;
7264
7265        if (size == unknown_size)
7266            return E_FILE_FORMAT_INVALID;  //not supported inside cluster
7267
7268        if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
7269            return E_FILE_FORMAT_INVALID;
7270
7271        if (id == 0x20)  //BlockGroup ID
7272            return 1;    //have at least one entry
7273
7274        if (id == 0x23)  //SimpleBlock ID
7275            return 1;    //have at least one entry
7276
7277        pos += size;  //consume payload
7278        assert((cluster_stop < 0) || (pos <= cluster_stop));
7279    }
7280}
7281
7282
7283long long Cluster::GetTimeCode() const
7284{
7285    long long pos;
7286    long len;
7287
7288    const long status = Load(pos, len);
7289
7290    if (status < 0) //error
7291        return status;
7292
7293    return m_timecode;
7294}
7295
7296
7297long long Cluster::GetTime() const
7298{
7299    const long long tc = GetTimeCode();
7300
7301    if (tc < 0)
7302        return tc;
7303
7304    const SegmentInfo* const pInfo = m_pSegment->GetInfo();
7305    assert(pInfo);
7306
7307    const long long scale = pInfo->GetTimeCodeScale();
7308    assert(scale >= 1);
7309
7310    const long long t = m_timecode * scale;
7311
7312    return t;
7313}
7314
7315
7316long long Cluster::GetFirstTime() const
7317{
7318    const BlockEntry* pEntry;
7319
7320    const long status = GetFirst(pEntry);
7321
7322    if (status < 0)  //error
7323        return status;
7324
7325    if (pEntry == NULL)  //empty cluster
7326        return GetTime();
7327
7328    const Block* const pBlock = pEntry->GetBlock();
7329    assert(pBlock);
7330
7331    return pBlock->GetTime(this);
7332}
7333
7334
7335long long Cluster::GetLastTime() const
7336{
7337    const BlockEntry* pEntry;
7338
7339    const long status = GetLast(pEntry);
7340
7341    if (status < 0)  //error
7342        return status;
7343
7344    if (pEntry == NULL)  //empty cluster
7345        return GetTime();
7346
7347    const Block* const pBlock = pEntry->GetBlock();
7348    assert(pBlock);
7349
7350    return pBlock->GetTime(this);
7351}
7352
7353
7354long Cluster::CreateBlock(
7355    long long id,
7356    long long pos,   //absolute pos of payload
7357    long long size)
7358{
7359    assert((id == 0x20) || (id == 0x23));  //BlockGroup or SimpleBlock
7360
7361    if (m_entries_count < 0)  //haven't parsed anything yet
7362    {
7363        assert(m_entries == NULL);
7364        assert(m_entries_size == 0);
7365
7366        m_entries_size = 1024;
7367        m_entries = new BlockEntry*[m_entries_size];
7368
7369        m_entries_count = 0;
7370    }
7371    else
7372    {
7373        assert(m_entries);
7374        assert(m_entries_size > 0);
7375        assert(m_entries_count <= m_entries_size);
7376
7377        if (m_entries_count >= m_entries_size)
7378        {
7379            const long entries_size = 2 * m_entries_size;
7380
7381            BlockEntry** const entries = new BlockEntry*[entries_size];
7382            assert(entries);
7383
7384            BlockEntry** src = m_entries;
7385            BlockEntry** const src_end = src + m_entries_count;
7386
7387            BlockEntry** dst = entries;
7388
7389            while (src != src_end)
7390                *dst++ = *src++;
7391
7392            delete[] m_entries;
7393
7394            m_entries = entries;
7395            m_entries_size = entries_size;
7396        }
7397    }
7398
7399    if (id == 0x20)  //BlockGroup ID
7400        return CreateBlockGroup(pos, size);
7401    else  //SimpleBlock ID
7402        return CreateSimpleBlock(pos, size);
7403}
7404
7405
7406long Cluster::CreateBlockGroup(
7407    long long st,
7408    long long sz)
7409{
7410    assert(m_entries);
7411    assert(m_entries_size > 0);
7412    assert(m_entries_count >= 0);
7413    assert(m_entries_count < m_entries_size);
7414
7415    IMkvReader* const pReader = m_pSegment->m_pReader;
7416
7417    long long pos = st;
7418    const long long stop = st + sz;
7419
7420    //For WebM files, there is a bias towards previous reference times
7421    //(in order to support alt-ref frames, which refer back to the previous
7422    //keyframe).  Normally a 0 value is not possible, but here we tenatively
7423    //allow 0 as the value of a reference frame, with the interpretation
7424    //that this is a "previous" reference time.
7425
7426    long long prev = 1;  //nonce
7427    long long next = 0;  //nonce
7428    long long duration = -1;  //really, this is unsigned
7429
7430    long long bpos = -1;
7431    long long bsize = -1;
7432
7433    while (pos < stop)
7434    {
7435        long len;
7436        const long long id = ReadUInt(pReader, pos, len);
7437        assert(id >= 0);  //TODO
7438        assert((pos + len) <= stop);
7439
7440        pos += len;  //consume ID
7441
7442        const long long size = ReadUInt(pReader, pos, len);
7443        assert(size >= 0);  //TODO
7444        assert((pos + len) <= stop);
7445
7446        pos += len;  //consume size
7447
7448        if (id == 0x21) //Block ID
7449        {
7450            if (bpos < 0) //Block ID
7451            {
7452                bpos = pos;
7453                bsize = size;
7454            }
7455        }
7456        else if (id == 0x1B)  //Duration ID
7457        {
7458            assert(size <= 8);
7459
7460            duration = UnserializeUInt(pReader, pos, size);
7461            assert(duration >= 0);  //TODO
7462        }
7463        else if (id == 0x7B)  //ReferenceBlock
7464        {
7465            assert(size <= 8);
7466            const long size_ = static_cast<long>(size);
7467
7468            long long time;
7469
7470            long status = UnserializeInt(pReader, pos, size_, time);
7471            assert(status == 0);  //TODO
7472
7473            if (time <= 0)  //see note above
7474                prev = time;
7475            else  //weird
7476                next = time;
7477        }
7478
7479        pos += size;  //consume payload
7480        assert(pos <= stop);
7481    }
7482
7483    assert(pos == stop);
7484    assert(bpos >= 0);
7485    assert(bsize >= 0);
7486
7487    const long idx = m_entries_count;
7488
7489    BlockEntry** const ppEntry = m_entries + idx;
7490    BlockEntry*& pEntry = *ppEntry;
7491
7492    pEntry = new (std::nothrow) BlockGroup(
7493                                  this,
7494                                  idx,
7495                                  bpos,
7496                                  bsize,
7497                                  prev,
7498                                  next,
7499                                  duration);
7500
7501    if (pEntry == NULL)
7502        return -1;  //generic error
7503
7504    BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
7505
7506    const long status = p->Parse();
7507
7508    if (status == 0)  //success
7509    {
7510        ++m_entries_count;
7511        return 0;
7512    }
7513
7514    delete pEntry;
7515    pEntry = 0;
7516
7517    return status;
7518}
7519
7520
7521
7522long Cluster::CreateSimpleBlock(
7523    long long st,
7524    long long sz)
7525{
7526    assert(m_entries);
7527    assert(m_entries_size > 0);
7528    assert(m_entries_count >= 0);
7529    assert(m_entries_count < m_entries_size);
7530
7531    const long idx = m_entries_count;
7532
7533    BlockEntry** const ppEntry = m_entries + idx;
7534    BlockEntry*& pEntry = *ppEntry;
7535
7536    pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
7537
7538    if (pEntry == NULL)
7539        return -1;  //generic error
7540
7541    SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
7542
7543    const long status = p->Parse();
7544
7545    if (status == 0)
7546    {
7547        ++m_entries_count;
7548        return 0;
7549    }
7550
7551    delete pEntry;
7552    pEntry = 0;
7553
7554    return status;
7555}
7556
7557
7558long Cluster::GetFirst(const BlockEntry*& pFirst) const
7559{
7560    if (m_entries_count <= 0)
7561    {
7562        long long pos;
7563        long len;
7564
7565        const long status = Parse(pos, len);
7566
7567        if (status < 0)  //error
7568        {
7569            pFirst = NULL;
7570            return status;
7571        }
7572
7573        if (m_entries_count <= 0)  //empty cluster
7574        {
7575            pFirst = NULL;
7576            return 0;
7577        }
7578    }
7579
7580    assert(m_entries);
7581
7582    pFirst = m_entries[0];
7583    assert(pFirst);
7584
7585    return 0;  //success
7586}
7587
7588long Cluster::GetLast(const BlockEntry*& pLast) const
7589{
7590    for (;;)
7591    {
7592        long long pos;
7593        long len;
7594
7595        const long status = Parse(pos, len);
7596
7597        if (status < 0)  //error
7598        {
7599            pLast = NULL;
7600            return status;
7601        }
7602
7603        if (status > 0)  //no new block
7604            break;
7605    }
7606
7607    if (m_entries_count <= 0)
7608    {
7609        pLast = NULL;
7610        return 0;
7611    }
7612
7613    assert(m_entries);
7614
7615    const long idx = m_entries_count - 1;
7616
7617    pLast = m_entries[idx];
7618    assert(pLast);
7619
7620    return 0;
7621}
7622
7623
7624long Cluster::GetNext(
7625    const BlockEntry* pCurr,
7626    const BlockEntry*& pNext) const
7627{
7628    assert(pCurr);
7629    assert(m_entries);
7630    assert(m_entries_count > 0);
7631
7632    size_t idx = pCurr->GetIndex();
7633    assert(idx < size_t(m_entries_count));
7634    assert(m_entries[idx] == pCurr);
7635
7636    ++idx;
7637
7638    if (idx >= size_t(m_entries_count))
7639    {
7640        long long pos;
7641        long len;
7642
7643        const long status = Parse(pos, len);
7644
7645        if (status < 0)  //error
7646        {
7647            pNext = NULL;
7648            return status;
7649        }
7650
7651        if (status > 0)
7652        {
7653            pNext = NULL;
7654            return 0;
7655        }
7656
7657        assert(m_entries);
7658        assert(m_entries_count > 0);
7659        assert(idx < size_t(m_entries_count));
7660    }
7661
7662    pNext = m_entries[idx];
7663    assert(pNext);
7664
7665    return 0;
7666}
7667
7668
7669long Cluster::GetEntryCount() const
7670{
7671    return m_entries_count;
7672}
7673
7674
7675const BlockEntry* Cluster::GetEntry(
7676    const Track* pTrack,
7677    long long time_ns) const
7678{
7679    assert(pTrack);
7680
7681    if (m_pSegment == NULL)  //this is the special EOS cluster
7682        return pTrack->GetEOS();
7683
7684#if 0
7685
7686    LoadBlockEntries();
7687
7688    if ((m_entries == NULL) || (m_entries_count <= 0))
7689        return NULL;  //return EOS here?
7690
7691    const BlockEntry* pResult = pTrack->GetEOS();
7692
7693    BlockEntry** i = m_entries;
7694    assert(i);
7695
7696    BlockEntry** const j = i + m_entries_count;
7697
7698    while (i != j)
7699    {
7700        const BlockEntry* const pEntry = *i++;
7701        assert(pEntry);
7702        assert(!pEntry->EOS());
7703
7704        const Block* const pBlock = pEntry->GetBlock();
7705        assert(pBlock);
7706
7707        if (pBlock->GetTrackNumber() != pTrack->GetNumber())
7708            continue;
7709
7710        if (pTrack->VetEntry(pEntry))
7711        {
7712            if (time_ns < 0)  //just want first candidate block
7713                return pEntry;
7714
7715            const long long ns = pBlock->GetTime(this);
7716
7717            if (ns > time_ns)
7718                break;
7719
7720            pResult = pEntry;
7721        }
7722        else if (time_ns >= 0)
7723        {
7724            const long long ns = pBlock->GetTime(this);
7725
7726            if (ns > time_ns)
7727                break;
7728        }
7729    }
7730
7731    return pResult;
7732
7733#else
7734
7735    const BlockEntry* pResult = pTrack->GetEOS();
7736
7737    long index = 0;
7738
7739    for (;;)
7740    {
7741        if (index >= m_entries_count)
7742        {
7743            long long pos;
7744            long len;
7745
7746            const long status = Parse(pos, len);
7747            assert(status >= 0);
7748
7749            if (status > 0)  //completely parsed, and no more entries
7750                return pResult;
7751
7752            if (status < 0)  //should never happen
7753                return 0;
7754
7755            assert(m_entries);
7756            assert(index < m_entries_count);
7757        }
7758
7759        const BlockEntry* const pEntry = m_entries[index];
7760        assert(pEntry);
7761        assert(!pEntry->EOS());
7762
7763        const Block* const pBlock = pEntry->GetBlock();
7764        assert(pBlock);
7765
7766        if (pBlock->GetTrackNumber() != pTrack->GetNumber())
7767        {
7768            ++index;
7769            continue;
7770        }
7771
7772        if (pTrack->VetEntry(pEntry))
7773        {
7774            if (time_ns < 0)  //just want first candidate block
7775                return pEntry;
7776
7777            const long long ns = pBlock->GetTime(this);
7778
7779            if (ns > time_ns)
7780                return pResult;
7781
7782            pResult = pEntry;  //have a candidate
7783        }
7784        else if (time_ns >= 0)
7785        {
7786            const long long ns = pBlock->GetTime(this);
7787
7788            if (ns > time_ns)
7789                return pResult;
7790        }
7791
7792        ++index;
7793    }
7794
7795#endif
7796}
7797
7798
7799const BlockEntry*
7800Cluster::GetEntry(
7801    const CuePoint& cp,
7802    const CuePoint::TrackPosition& tp) const
7803{
7804    assert(m_pSegment);
7805
7806#if 0
7807
7808    LoadBlockEntries();
7809
7810    if (m_entries == NULL)
7811        return NULL;
7812
7813    const long long count = m_entries_count;
7814
7815    if (count <= 0)
7816        return NULL;
7817
7818    const long long tc = cp.GetTimeCode();
7819
7820    if ((tp.m_block > 0) && (tp.m_block <= count))
7821    {
7822        const size_t block = static_cast<size_t>(tp.m_block);
7823        const size_t index = block - 1;
7824
7825        const BlockEntry* const pEntry = m_entries[index];
7826        assert(pEntry);
7827        assert(!pEntry->EOS());
7828
7829        const Block* const pBlock = pEntry->GetBlock();
7830        assert(pBlock);
7831
7832        if ((pBlock->GetTrackNumber() == tp.m_track) &&
7833            (pBlock->GetTimeCode(this) == tc))
7834        {
7835            return pEntry;
7836        }
7837    }
7838
7839    const BlockEntry* const* i = m_entries;
7840    const BlockEntry* const* const j = i + count;
7841
7842    while (i != j)
7843    {
7844#ifdef _DEBUG
7845        const ptrdiff_t idx = i - m_entries;
7846        idx;
7847#endif
7848
7849        const BlockEntry* const pEntry = *i++;
7850        assert(pEntry);
7851        assert(!pEntry->EOS());
7852
7853        const Block* const pBlock = pEntry->GetBlock();
7854        assert(pBlock);
7855
7856        if (pBlock->GetTrackNumber() != tp.m_track)
7857            continue;
7858
7859        const long long tc_ = pBlock->GetTimeCode(this);
7860        assert(tc_ >= 0);
7861
7862        if (tc_ < tc)
7863            continue;
7864
7865        if (tc_ > tc)
7866            return NULL;
7867
7868        const Tracks* const pTracks = m_pSegment->GetTracks();
7869        assert(pTracks);
7870
7871        const long tn = static_cast<long>(tp.m_track);
7872        const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7873
7874        if (pTrack == NULL)
7875            return NULL;
7876
7877        const long long type = pTrack->GetType();
7878
7879        if (type == 2)  //audio
7880            return pEntry;
7881
7882        if (type != 1)  //not video
7883            return NULL;
7884
7885        if (!pBlock->IsKey())
7886            return NULL;
7887
7888        return pEntry;
7889    }
7890
7891    return NULL;
7892
7893#else
7894
7895    const long long tc = cp.GetTimeCode();
7896
7897    if (tp.m_block > 0)
7898    {
7899        const long block = static_cast<long>(tp.m_block);
7900        const long index = block - 1;
7901
7902        while (index >= m_entries_count)
7903        {
7904            long long pos;
7905            long len;
7906
7907            const long status = Parse(pos, len);
7908
7909            if (status < 0)  //TODO: can this happen?
7910                return NULL;
7911
7912            if (status > 0)  //nothing remains to be parsed
7913                return NULL;
7914        }
7915
7916        const BlockEntry* const pEntry = m_entries[index];
7917        assert(pEntry);
7918        assert(!pEntry->EOS());
7919
7920        const Block* const pBlock = pEntry->GetBlock();
7921        assert(pBlock);
7922
7923        if ((pBlock->GetTrackNumber() == tp.m_track) &&
7924            (pBlock->GetTimeCode(this) == tc))
7925        {
7926            return pEntry;
7927        }
7928    }
7929
7930    long index = 0;
7931
7932    for (;;)
7933    {
7934        if (index >= m_entries_count)
7935        {
7936            long long pos;
7937            long len;
7938
7939            const long status = Parse(pos, len);
7940
7941            if (status < 0)  //TODO: can this happen?
7942                return NULL;
7943
7944            if (status > 0)  //nothing remains to be parsed
7945                return NULL;
7946
7947            assert(m_entries);
7948            assert(index < m_entries_count);
7949        }
7950
7951        const BlockEntry* const pEntry = m_entries[index];
7952        assert(pEntry);
7953        assert(!pEntry->EOS());
7954
7955        const Block* const pBlock = pEntry->GetBlock();
7956        assert(pBlock);
7957
7958        if (pBlock->GetTrackNumber() != tp.m_track)
7959        {
7960            ++index;
7961            continue;
7962        }
7963
7964        const long long tc_ = pBlock->GetTimeCode(this);
7965        assert(tc_ >= 0);
7966
7967        if (tc_ < tc)
7968        {
7969            ++index;
7970            continue;
7971        }
7972
7973        if (tc_ > tc)
7974            return NULL;
7975
7976        const Tracks* const pTracks = m_pSegment->GetTracks();
7977        assert(pTracks);
7978
7979        const long tn = static_cast<long>(tp.m_track);
7980        const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7981
7982        if (pTrack == NULL)
7983            return NULL;
7984
7985        const long long type = pTrack->GetType();
7986
7987        if (type == 2)  //audio
7988            return pEntry;
7989
7990        if (type != 1)  //not video
7991            return NULL;
7992
7993        if (!pBlock->IsKey())
7994            return NULL;
7995
7996        return pEntry;
7997    }
7998
7999#endif
8000
8001}
8002
8003
8004#if 0
8005const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const
8006{
8007    assert(pTrack);
8008
8009    if (m_pSegment == NULL)  //EOS
8010        return pTrack->GetEOS();
8011
8012    LoadBlockEntries();
8013
8014    if ((m_entries == NULL) || (m_entries_count <= 0))
8015        return pTrack->GetEOS();
8016
8017    BlockEntry** i = m_entries + m_entries_count;
8018    BlockEntry** const j = m_entries;
8019
8020    while (i != j)
8021    {
8022        const BlockEntry* const pEntry = *--i;
8023        assert(pEntry);
8024        assert(!pEntry->EOS());
8025
8026        const Block* const pBlock = pEntry->GetBlock();
8027        assert(pBlock);
8028
8029        if (pBlock->GetTrackNumber() != pTrack->GetNumber())
8030            continue;
8031
8032        if (pBlock->IsKey())
8033            return pEntry;
8034    }
8035
8036    return pTrack->GetEOS();  //no satisfactory block found
8037}
8038#endif
8039
8040
8041BlockEntry::BlockEntry(Cluster* p, long idx) :
8042    m_pCluster(p),
8043    m_index(idx)
8044{
8045}
8046
8047
8048BlockEntry::~BlockEntry()
8049{
8050}
8051
8052
8053bool BlockEntry::EOS() const
8054{
8055    return (GetKind() == kBlockEOS);
8056}
8057
8058
8059const Cluster* BlockEntry::GetCluster() const
8060{
8061    return m_pCluster;
8062}
8063
8064
8065long BlockEntry::GetIndex() const
8066{
8067    return m_index;
8068}
8069
8070
8071SimpleBlock::SimpleBlock(
8072    Cluster* pCluster,
8073    long idx,
8074    long long start,
8075    long long size) :
8076    BlockEntry(pCluster, idx),
8077    m_block(start, size)
8078{
8079}
8080
8081
8082long SimpleBlock::Parse()
8083{
8084    return m_block.Parse(m_pCluster->m_pSegment->m_pReader);
8085}
8086
8087
8088BlockEntry::Kind SimpleBlock::GetKind() const
8089{
8090    return kBlockSimple;
8091}
8092
8093
8094const Block* SimpleBlock::GetBlock() const
8095{
8096    return &m_block;
8097}
8098
8099
8100BlockGroup::BlockGroup(
8101    Cluster* pCluster,
8102    long idx,
8103    long long block_start,
8104    long long block_size,
8105    long long prev,
8106    long long next,
8107    long long duration) :
8108    BlockEntry(pCluster, idx),
8109    m_block(block_start, block_size),
8110    m_prev(prev),
8111    m_next(next),
8112    m_duration(duration)
8113{
8114}
8115
8116
8117long BlockGroup::Parse()
8118{
8119    const long status = m_block.Parse(m_pCluster->m_pSegment->m_pReader);
8120
8121    if (status)
8122        return status;
8123
8124    m_block.SetKey((m_prev > 0) && (m_next <= 0));
8125
8126    return 0;
8127}
8128
8129
8130#if 0
8131void BlockGroup::ParseBlock(long long start, long long size)
8132{
8133    IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
8134
8135    Block* const pBlock = new Block(start, size, pReader);
8136    assert(pBlock);  //TODO
8137
8138    //TODO: the Matroska spec says you have multiple blocks within the
8139    //same block group, with blocks ranked by priority (the flag bits).
8140
8141    assert(m_pBlock == NULL);
8142    m_pBlock = pBlock;
8143}
8144#endif
8145
8146
8147BlockEntry::Kind BlockGroup::GetKind() const
8148{
8149    return kBlockGroup;
8150}
8151
8152
8153const Block* BlockGroup::GetBlock() const
8154{
8155    return &m_block;
8156}
8157
8158
8159long long BlockGroup::GetPrevTimeCode() const
8160{
8161    return m_prev;
8162}
8163
8164
8165long long BlockGroup::GetNextTimeCode() const
8166{
8167    return m_next;
8168}
8169
8170
8171Block::Block(long long start, long long size_) :
8172    m_start(start),
8173    m_size(size_),
8174    m_track(0),
8175    m_timecode(-1),
8176    m_flags(0),
8177    m_frames(NULL),
8178    m_frame_count(-1)
8179{
8180}
8181
8182
8183Block::~Block()
8184{
8185    delete[] m_frames;
8186}
8187
8188
8189long Block::Parse(IMkvReader* pReader)
8190{
8191    assert(pReader);
8192    assert(m_start >= 0);
8193    assert(m_size >= 0);
8194    assert(m_track <= 0);
8195    assert(m_frames == NULL);
8196    assert(m_frame_count <= 0);
8197
8198    long long pos = m_start;
8199    const long long stop = m_start + m_size;
8200
8201    long len;
8202
8203    m_track = ReadUInt(pReader, pos, len);
8204
8205    if (m_track <= 0)
8206        return E_FILE_FORMAT_INVALID;
8207
8208    if ((pos + len) > stop)
8209        return E_FILE_FORMAT_INVALID;
8210
8211    pos += len;  //consume track number
8212
8213    if ((stop - pos) < 2)
8214        return E_FILE_FORMAT_INVALID;
8215
8216    long status;
8217    long long value;
8218
8219    status = UnserializeInt(pReader, pos, 2, value);
8220
8221    if (status)
8222        return E_FILE_FORMAT_INVALID;
8223
8224    if (value < SHRT_MIN)
8225        return E_FILE_FORMAT_INVALID;
8226
8227    if (value > SHRT_MAX)
8228        return E_FILE_FORMAT_INVALID;
8229
8230    m_timecode = static_cast<short>(value);
8231
8232    pos += 2;
8233
8234    if ((stop - pos) <= 0)
8235        return E_FILE_FORMAT_INVALID;
8236
8237    status = pReader->Read(pos, 1, &m_flags);
8238
8239    if (status)
8240        return E_FILE_FORMAT_INVALID;
8241
8242    const int lacing = int(m_flags & 0x06) >> 1;
8243
8244    ++pos;  //consume flags byte
8245
8246    if (lacing == 0)  //no lacing
8247    {
8248        if (pos > stop)
8249            return E_FILE_FORMAT_INVALID;
8250
8251        m_frame_count = 1;
8252        m_frames = new Frame[m_frame_count];
8253
8254        Frame& f = m_frames[0];
8255        f.pos = pos;
8256
8257        const long long frame_size = stop - pos;
8258
8259        if (frame_size > LONG_MAX)
8260            return E_FILE_FORMAT_INVALID;
8261
8262        f.len = static_cast<long>(frame_size);
8263
8264        return 0;  //success
8265    }
8266
8267    if (pos >= stop)
8268        return E_FILE_FORMAT_INVALID;
8269
8270    unsigned char biased_count;
8271
8272    status = pReader->Read(pos, 1, &biased_count);
8273
8274    if (status)
8275        return E_FILE_FORMAT_INVALID;
8276
8277    ++pos;  //consume frame count
8278    assert(pos <= stop);
8279
8280    m_frame_count = int(biased_count) + 1;
8281
8282    m_frames = new Frame[m_frame_count];
8283    assert(m_frames);
8284
8285    if (lacing == 1)  //Xiph
8286    {
8287        Frame* pf = m_frames;
8288        Frame* const pf_end = pf + m_frame_count;
8289
8290        long size = 0;
8291        int frame_count = m_frame_count;
8292
8293        while (frame_count > 1)
8294        {
8295            long frame_size = 0;
8296
8297            for (;;)
8298            {
8299                unsigned char val;
8300
8301                if (pos >= stop)
8302                    return E_FILE_FORMAT_INVALID;
8303
8304                status = pReader->Read(pos, 1, &val);
8305
8306                if (status)
8307                    return E_FILE_FORMAT_INVALID;
8308
8309                ++pos;  //consume xiph size byte
8310
8311                frame_size += val;
8312
8313                if (val < 255)
8314                    break;
8315            }
8316
8317            Frame& f = *pf++;
8318            assert(pf < pf_end);
8319
8320            f.pos = 0;  //patch later
8321
8322            f.len = frame_size;
8323            size += frame_size;  //contribution of this frame
8324
8325            --frame_count;
8326        }
8327
8328        assert(pf < pf_end);
8329        assert(pos <= stop);
8330
8331        {
8332            Frame& f = *pf++;
8333
8334            if (pf != pf_end)
8335                return E_FILE_FORMAT_INVALID;
8336
8337            f.pos = 0;  //patch later
8338
8339            const long long total_size = stop - pos;
8340
8341            if (total_size < size)
8342                return E_FILE_FORMAT_INVALID;
8343
8344            const long long frame_size = total_size - size;
8345
8346            if (frame_size > LONG_MAX)
8347                return E_FILE_FORMAT_INVALID;
8348
8349            f.len = static_cast<long>(frame_size);
8350        }
8351
8352        pf = m_frames;
8353        while (pf != pf_end)
8354        {
8355            Frame& f = *pf++;
8356            assert((pos + f.len) <= stop);
8357
8358            f.pos = pos;
8359            pos += f.len;
8360        }
8361
8362        assert(pos == stop);
8363    }
8364    else if (lacing == 2)  //fixed-size lacing
8365    {
8366        const long long total_size = stop - pos;
8367
8368        if ((total_size % m_frame_count) != 0)
8369            return E_FILE_FORMAT_INVALID;
8370
8371        const long long frame_size = total_size / m_frame_count;
8372
8373        if (frame_size > LONG_MAX)
8374            return E_FILE_FORMAT_INVALID;
8375
8376        Frame* pf = m_frames;
8377        Frame* const pf_end = pf + m_frame_count;
8378
8379        while (pf != pf_end)
8380        {
8381            assert((pos + frame_size) <= stop);
8382
8383            Frame& f = *pf++;
8384
8385            f.pos = pos;
8386            f.len = static_cast<long>(frame_size);
8387
8388            pos += frame_size;
8389        }
8390
8391        assert(pos == stop);
8392    }
8393    else
8394    {
8395        assert(lacing == 3);  //EBML lacing
8396
8397        if (pos >= stop)
8398            return E_FILE_FORMAT_INVALID;
8399
8400        long size = 0;
8401        int frame_count = m_frame_count;
8402
8403        long long frame_size = ReadUInt(pReader, pos, len);
8404
8405        if (frame_size < 0)
8406            return E_FILE_FORMAT_INVALID;
8407
8408        if (frame_size > LONG_MAX)
8409            return E_FILE_FORMAT_INVALID;
8410
8411        if ((pos + len) > stop)
8412            return E_FILE_FORMAT_INVALID;
8413
8414        pos += len; //consume length of size of first frame
8415
8416        if ((pos + frame_size) > stop)
8417            return E_FILE_FORMAT_INVALID;
8418
8419        Frame* pf = m_frames;
8420        Frame* const pf_end = pf + m_frame_count;
8421
8422        {
8423            Frame& curr = *pf;
8424
8425            curr.pos = 0;  //patch later
8426
8427            curr.len = static_cast<long>(frame_size);
8428            size += curr.len;  //contribution of this frame
8429        }
8430
8431        --frame_count;
8432
8433        while (frame_count > 1)
8434        {
8435            if (pos >= stop)
8436                return E_FILE_FORMAT_INVALID;
8437
8438            assert(pf < pf_end);
8439
8440            const Frame& prev = *pf++;
8441            assert(prev.len == frame_size);
8442
8443            assert(pf < pf_end);
8444
8445            Frame& curr = *pf;
8446
8447            curr.pos = 0;  //patch later
8448
8449            const long long delta_size_ = ReadUInt(pReader, pos, len);
8450
8451            if (delta_size_ < 0)
8452                return E_FILE_FORMAT_INVALID;
8453
8454            if ((pos + len) > stop)
8455                return E_FILE_FORMAT_INVALID;
8456
8457            pos += len;  //consume length of (delta) size
8458            assert(pos <= stop);
8459
8460            const int exp = 7*len - 1;
8461            const long long bias = (1LL << exp) - 1LL;
8462            const long long delta_size = delta_size_ - bias;
8463
8464            frame_size += delta_size;
8465
8466            if (frame_size < 0)
8467                return E_FILE_FORMAT_INVALID;
8468
8469            if (frame_size > LONG_MAX)
8470                return E_FILE_FORMAT_INVALID;
8471
8472            curr.len = static_cast<long>(frame_size);
8473            size += curr.len;  //contribution of this frame
8474
8475            --frame_count;
8476        }
8477
8478        {
8479            assert(pos <= stop);
8480            assert(pf < pf_end);
8481
8482            const Frame& prev = *pf++;
8483            assert(prev.len == frame_size);
8484
8485            assert(pf < pf_end);
8486
8487            Frame& curr = *pf++;
8488            assert(pf == pf_end);
8489
8490            curr.pos = 0;  //patch later
8491
8492            const long long total_size = stop - pos;
8493
8494            if (total_size < size)
8495                return E_FILE_FORMAT_INVALID;
8496
8497            frame_size = total_size - size;
8498
8499            if (frame_size > LONG_MAX)
8500                return E_FILE_FORMAT_INVALID;
8501
8502            curr.len = static_cast<long>(frame_size);
8503        }
8504
8505        pf = m_frames;
8506        while (pf != pf_end)
8507        {
8508            Frame& f = *pf++;
8509            assert((pos + f.len) <= stop);
8510
8511            f.pos = pos;
8512            pos += f.len;
8513        }
8514
8515        assert(pos == stop);
8516    }
8517
8518    return 0;  //success
8519}
8520
8521
8522long long Block::GetTimeCode(const Cluster* pCluster) const
8523{
8524    if (pCluster == 0)
8525        return m_timecode;
8526
8527    const long long tc0 = pCluster->GetTimeCode();
8528    assert(tc0 >= 0);
8529
8530    const long long tc = tc0 + m_timecode;
8531    assert(tc >= 0);
8532
8533    return tc;  //unscaled timecode units
8534}
8535
8536
8537long long Block::GetTime(const Cluster* pCluster) const
8538{
8539    assert(pCluster);
8540
8541    const long long tc = GetTimeCode(pCluster);
8542
8543    const Segment* const pSegment = pCluster->m_pSegment;
8544    const SegmentInfo* const pInfo = pSegment->GetInfo();
8545    assert(pInfo);
8546
8547    const long long scale = pInfo->GetTimeCodeScale();
8548    assert(scale >= 1);
8549
8550    const long long ns = tc * scale;
8551
8552    return ns;
8553}
8554
8555
8556long long Block::GetTrackNumber() const
8557{
8558    return m_track;
8559}
8560
8561
8562bool Block::IsKey() const
8563{
8564    return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
8565}
8566
8567
8568void Block::SetKey(bool bKey)
8569{
8570    if (bKey)
8571        m_flags |= static_cast<unsigned char>(1 << 7);
8572    else
8573        m_flags &= 0x7F;
8574}
8575
8576
8577bool Block::IsInvisible() const
8578{
8579    return bool(int(m_flags & 0x08) != 0);
8580}
8581
8582
8583Block::Lacing Block::GetLacing() const
8584{
8585    const int value = int(m_flags & 0x06) >> 1;
8586    return static_cast<Lacing>(value);
8587}
8588
8589
8590int Block::GetFrameCount() const
8591{
8592    return m_frame_count;
8593}
8594
8595
8596const Block::Frame& Block::GetFrame(int idx) const
8597{
8598    assert(idx >= 0);
8599    assert(idx < m_frame_count);
8600
8601    const Frame& f = m_frames[idx];
8602    assert(f.pos > 0);
8603    assert(f.len > 0);
8604
8605    return f;
8606}
8607
8608
8609long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const
8610{
8611    assert(pReader);
8612    assert(buf);
8613
8614    const long status = pReader->Read(pos, len, buf);
8615    return status;
8616}
8617
8618
8619}  //end namespace mkvparser
8620