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