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