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