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