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