Home | History | Annotate | Download | only in matroska
      1 #include "mkvparser.hpp"
      2 #include <cassert>
      3 #include <cstring>
      4 
      5 mkvparser::IMkvReader::~IMkvReader()
      6 {
      7 }
      8 
      9 long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
     10 {
     11     assert(pReader);
     12     assert(pos >= 0);
     13 
     14     long long total, available;
     15 
     16     long hr = pReader->Length(&total, &available);
     17     assert(hr >= 0);
     18     assert(pos < available);
     19     assert((available - pos) >= 1);  //assume here max u-int len is 8
     20 
     21     unsigned char b;
     22 
     23     hr = pReader->Read(pos, 1, &b);
     24     if (hr < 0)
     25         return hr;
     26 
     27     assert(hr == 0L);
     28 
     29     if (b & 0x80)       //1000 0000
     30     {
     31         len = 1;
     32         b &= 0x7F;      //0111 1111
     33     }
     34     else if (b & 0x40)  //0100 0000
     35     {
     36         len = 2;
     37         b &= 0x3F;      //0011 1111
     38     }
     39     else if (b & 0x20)  //0010 0000
     40     {
     41         len = 3;
     42         b &= 0x1F;      //0001 1111
     43     }
     44     else if (b & 0x10)  //0001 0000
     45     {
     46         len = 4;
     47         b &= 0x0F;      //0000 1111
     48     }
     49     else if (b & 0x08)  //0000 1000
     50     {
     51         len = 5;
     52         b &= 0x07;      //0000 0111
     53     }
     54     else if (b & 0x04)  //0000 0100
     55     {
     56         len = 6;
     57         b &= 0x03;      //0000 0011
     58     }
     59     else if (b & 0x02)  //0000 0010
     60     {
     61         len = 7;
     62         b &= 0x01;      //0000 0001
     63     }
     64     else
     65     {
     66         assert(b & 0x01);  //0000 0001
     67         len = 8;
     68         b = 0;             //0000 0000
     69     }
     70 
     71     assert((available - pos) >= len);
     72 
     73     long long result = b;
     74     ++pos;
     75     for (long i = 1; i < len; ++i)
     76     {
     77         hr = pReader->Read(pos, 1, &b);
     78 
     79         if (hr < 0)
     80             return hr;
     81 
     82         assert(hr == 0L);
     83 
     84         result <<= 8;
     85         result |= b;
     86 
     87         ++pos;
     88     }
     89 
     90     return result;
     91 }
     92 
     93 
     94 long long mkvparser::GetUIntLength(
     95     IMkvReader* pReader,
     96     long long pos,
     97     long& len)
     98 {
     99     assert(pReader);
    100     assert(pos >= 0);
    101 
    102     long long total, available;
    103 
    104     long hr = pReader->Length(&total, &available);
    105     assert(hr >= 0);
    106     assert(available <= total);
    107 
    108     if (pos >= available)
    109         return pos;  //too few bytes available
    110 
    111     unsigned char b;
    112 
    113     hr = pReader->Read(pos, 1, &b);
    114 
    115     if (hr < 0)
    116         return hr;
    117 
    118     assert(hr == 0L);
    119 
    120     if (b == 0)  //we can't handle u-int values larger than 8 bytes
    121         return E_FILE_FORMAT_INVALID;
    122 
    123     unsigned char m = 0x80;
    124     len = 1;
    125 
    126     while (!(b & m))
    127     {
    128         m >>= 1;
    129         ++len;
    130     }
    131 
    132     return 0;  //success
    133 }
    134 
    135 
    136 long long mkvparser::SyncReadUInt(
    137     IMkvReader* pReader,
    138     long long pos,
    139     long long stop,
    140     long& len)
    141 {
    142     assert(pReader);
    143 
    144     if (pos >= stop)
    145         return E_FILE_FORMAT_INVALID;
    146 
    147     unsigned char b;
    148 
    149     long hr = pReader->Read(pos, 1, &b);
    150 
    151     if (hr < 0)
    152         return hr;
    153 
    154     if (hr != 0L)
    155         return E_BUFFER_NOT_FULL;
    156 
    157     if (b == 0)  //we can't handle u-int values larger than 8 bytes
    158         return E_FILE_FORMAT_INVALID;
    159 
    160     unsigned char m = 0x80;
    161     len = 1;
    162 
    163     while (!(b & m))
    164     {
    165         m >>= 1;
    166         ++len;
    167     }
    168 
    169     if ((pos + len) > stop)
    170         return E_FILE_FORMAT_INVALID;
    171 
    172     long long result = b & (~m);
    173     ++pos;
    174 
    175     for (int i = 1; i < len; ++i)
    176     {
    177         hr = pReader->Read(pos, 1, &b);
    178 
    179         if (hr < 0)
    180             return hr;
    181 
    182         if (hr != 0L)
    183             return E_BUFFER_NOT_FULL;
    184 
    185         result <<= 8;
    186         result |= b;
    187 
    188         ++pos;
    189     }
    190 
    191     return result;
    192 }
    193 
    194 
    195 long long mkvparser::UnserializeUInt(
    196     IMkvReader* pReader,
    197     long long pos,
    198     long long size)
    199 {
    200     assert(pReader);
    201     assert(pos >= 0);
    202     assert(size > 0);
    203     assert(size <= 8);
    204 
    205     long long result = 0;
    206 
    207     for (long long i = 0; i < size; ++i)
    208     {
    209         unsigned char b;
    210 
    211         const long hr = pReader->Read(pos, 1, &b);
    212 
    213         if (hr < 0)
    214             return hr;
    215         result <<= 8;
    216         result |= b;
    217 
    218         ++pos;
    219     }
    220 
    221     return result;
    222 }
    223 
    224 
    225 float mkvparser::Unserialize4Float(
    226     IMkvReader* pReader,
    227     long long pos)
    228 {
    229     assert(pReader);
    230     assert(pos >= 0);
    231 
    232     long long total, available;
    233 
    234     long hr = pReader->Length(&total, &available);
    235     assert(hr >= 0);
    236     assert(available <= total);
    237     assert((pos + 4) <= available);
    238 
    239     float result;
    240 
    241     unsigned char* const p = (unsigned char*)&result;
    242     unsigned char* q = p + 4;
    243 
    244     for (;;)
    245     {
    246         hr = pReader->Read(pos, 1, --q);
    247         assert(hr == 0L);
    248 
    249         if (q == p)
    250             break;
    251 
    252         ++pos;
    253     }
    254 
    255     return result;
    256 }
    257 
    258 
    259 double mkvparser::Unserialize8Double(
    260     IMkvReader* pReader,
    261     long long pos)
    262 {
    263     assert(pReader);
    264     assert(pos >= 0);
    265 
    266     double result;
    267 
    268     unsigned char* const p = (unsigned char*)&result;
    269     unsigned char* q = p + 8;
    270 
    271     for (;;)
    272     {
    273         const long hr = pReader->Read(pos, 1, --q);
    274         assert(hr == 0L);
    275 
    276         if (q == p)
    277             break;
    278 
    279         ++pos;
    280     }
    281 
    282     return result;
    283 }
    284 
    285 signed char mkvparser::Unserialize1SInt(
    286     IMkvReader* pReader,
    287     long long pos)
    288 {
    289     assert(pReader);
    290     assert(pos >= 0);
    291 
    292     long long total, available;
    293 
    294     long hr = pReader->Length(&total, &available);
    295     assert(hr == 0);
    296     assert(available <= total);
    297     assert(pos < available);
    298 
    299     signed char result;
    300 
    301     hr = pReader->Read(pos, 1, (unsigned char*)&result);
    302     assert(hr == 0);
    303 
    304     return result;
    305 }
    306 
    307 short mkvparser::Unserialize2SInt(
    308     IMkvReader* pReader,
    309     long long pos)
    310 {
    311     assert(pReader);
    312     assert(pos >= 0);
    313 
    314     long long total, available;
    315 
    316     long hr = pReader->Length(&total, &available);
    317     assert(hr >= 0);
    318     assert(available <= total);
    319     assert((pos + 2) <= available);
    320 
    321     short result;
    322 
    323     unsigned char* const p = (unsigned char*)&result;
    324     unsigned char* q = p + 2;
    325 
    326     for (;;)
    327     {
    328         hr = pReader->Read(pos, 1, --q);
    329         assert(hr == 0L);
    330 
    331         if (q == p)
    332             break;
    333 
    334         ++pos;
    335     }
    336 
    337     return result;
    338 }
    339 
    340 
    341 bool mkvparser::Match(
    342     IMkvReader* pReader,
    343     long long& pos,
    344     unsigned long id_,
    345     long long& val)
    346 
    347 {
    348     assert(pReader);
    349     assert(pos >= 0);
    350 
    351     long long total, available;
    352 
    353     long hr = pReader->Length(&total, &available);
    354     assert(hr >= 0);
    355     assert(available <= total);
    356 
    357     long len;
    358 
    359     const long long id = ReadUInt(pReader, pos, len);
    360     assert(id >= 0);
    361     assert(len > 0);
    362     assert(len <= 8);
    363     assert((pos + len) <= available);
    364 
    365     if ((unsigned long)id != id_)
    366         return false;
    367 
    368     pos += len;  //consume id
    369 
    370     const long long size = ReadUInt(pReader, pos, len);
    371     assert(size >= 0);
    372     assert(size <= 8);
    373     assert(len > 0);
    374     assert(len <= 8);
    375     assert((pos + len) <= available);
    376 
    377     pos += len;  //consume length of size of payload
    378 
    379     val = UnserializeUInt(pReader, pos, size);
    380     assert(val >= 0);
    381 
    382     pos += size;  //consume size of payload
    383 
    384     return true;
    385 }
    386 
    387 bool mkvparser::Match(
    388     IMkvReader* pReader,
    389     long long& pos,
    390     unsigned long id_,
    391     char*& val)
    392 {
    393     assert(pReader);
    394     assert(pos >= 0);
    395 
    396     long long total, available;
    397 
    398     long hr = pReader->Length(&total, &available);
    399     assert(hr >= 0);
    400     assert(available <= total);
    401 
    402     long len;
    403 
    404     const long long id = ReadUInt(pReader, pos, len);
    405     assert(id >= 0);
    406     assert(len > 0);
    407     assert(len <= 8);
    408     assert((pos + len) <= available);
    409 
    410     if ((unsigned long)id != id_)
    411         return false;
    412 
    413     pos += len;  //consume id
    414 
    415     const long long size_ = ReadUInt(pReader, pos, len);
    416     assert(size_ >= 0);
    417     assert(len > 0);
    418     assert(len <= 8);
    419     assert((pos + len) <= available);
    420 
    421     pos += len;  //consume length of size of payload
    422     assert((pos + size_) <= available);
    423 
    424     const size_t size = static_cast<size_t>(size_);
    425     val = new char[size+1];
    426 
    427     for (size_t i = 0; i < size; ++i)
    428     {
    429         char c;
    430 
    431         hr = pReader->Read(pos + i, 1, (unsigned char*)&c);
    432         assert(hr == 0L);
    433 
    434         val[i] = c;
    435 
    436         if (c == '\0')
    437             break;
    438 
    439     }
    440 
    441     val[size] = '\0';
    442     pos += size_;  //consume size of payload
    443 
    444     return true;
    445 }
    446 
    447 #if 0
    448 bool mkvparser::Match(
    449     IMkvReader* pReader,
    450     long long& pos,
    451     unsigned long id,
    452     wchar_t*& val)
    453 {
    454     char* str;
    455 
    456     if (!Match(pReader, pos, id, str))
    457         return false;
    458 
    459     const size_t size = mbstowcs(NULL, str, 0);
    460 
    461     if (size == 0)
    462         val = NULL;
    463     else
    464     {
    465         val = new wchar_t[size+1];
    466         mbstowcs(val, str, size);
    467         val[size] = L'\0';
    468     }
    469 
    470     delete[] str;
    471     return true;
    472 }
    473 #endif
    474 
    475 
    476 bool mkvparser::Match(
    477     IMkvReader* pReader,
    478     long long& pos,
    479     unsigned long id_,
    480     unsigned char*& val,
    481     size_t *optionalSize)
    482 {
    483     assert(pReader);
    484     assert(pos >= 0);
    485 
    486     long long total, available;
    487 
    488     long hr = pReader->Length(&total, &available);
    489     assert(hr >= 0);
    490     assert(available <= total);
    491 
    492     long len;
    493     const long long id = ReadUInt(pReader, pos, len);
    494     assert(id >= 0);
    495     assert(len > 0);
    496     assert(len <= 8);
    497     assert((pos + len) <= available);
    498 
    499     if ((unsigned long)id != id_)
    500         return false;
    501 
    502     pos += len;  //consume id
    503 
    504     const long long size_ = ReadUInt(pReader, pos, len);
    505     assert(size_ >= 0);
    506     assert(len > 0);
    507     assert(len <= 8);
    508     assert((pos + len) <= available);
    509 
    510     pos += len;  //consume length of size of payload
    511     assert((pos + size_) <= available);
    512 
    513     const size_t size = static_cast<size_t>(size_);
    514     val = new unsigned char[size];
    515 
    516     if (optionalSize) {
    517         *optionalSize = size;
    518     }
    519 
    520     for (size_t i = 0; i < size; ++i)
    521     {
    522         unsigned char b;
    523 
    524         hr = pReader->Read(pos + i, 1, &b);
    525         assert(hr == 0L);
    526 
    527         val[i] = b;
    528     }
    529 
    530     pos += size_;  //consume size of payload
    531     return true;
    532 }
    533 
    534 
    535 bool mkvparser::Match(
    536     IMkvReader* pReader,
    537     long long& pos,
    538     unsigned long id_,
    539     double& val)
    540 {
    541     assert(pReader);
    542     assert(pos >= 0);
    543 
    544     long long total, available;
    545 
    546     long hr = pReader->Length(&total, &available);
    547     assert(hr >= 0);
    548     assert(available <= total);
    549     long idlen;
    550     const long long id = ReadUInt(pReader, pos, idlen);
    551     assert(id >= 0);  //TODO
    552 
    553     if ((unsigned long)id != id_)
    554         return false;
    555 
    556     long sizelen;
    557     const long long size = ReadUInt(pReader, pos + idlen, sizelen);
    558 
    559     switch (size)
    560     {
    561         case 4:
    562         case 8:
    563             break;
    564         default:
    565             return false;
    566     }
    567 
    568     pos += idlen + sizelen;  //consume id and size fields
    569     assert((pos + size) <= available);
    570 
    571     if (size == 4)
    572         val = Unserialize4Float(pReader, pos);
    573     else
    574     {
    575         assert(size == 8);
    576         val = Unserialize8Double(pReader, pos);
    577     }
    578 
    579     pos += size;  //consume size of payload
    580 
    581     return true;
    582 }
    583 
    584 
    585 bool mkvparser::Match(
    586     IMkvReader* pReader,
    587     long long& pos,
    588     unsigned long id_,
    589     short& val)
    590 {
    591     assert(pReader);
    592     assert(pos >= 0);
    593 
    594     long long total, available;
    595 
    596     long hr = pReader->Length(&total, &available);
    597     assert(hr >= 0);
    598     assert(available <= total);
    599 
    600     long len;
    601     const long long id = ReadUInt(pReader, pos, len);
    602     assert(id >= 0);
    603     assert((pos + len) <= available);
    604 
    605     if ((unsigned long)id != id_)
    606         return false;
    607 
    608     pos += len;  //consume id
    609 
    610     const long long size = ReadUInt(pReader, pos, len);
    611     assert(size <= 2);
    612     assert((pos + len) <= available);
    613 
    614     pos += len;  //consume length of size of payload
    615     assert((pos + size) <= available);
    616 
    617     //TODO:
    618     // Generalize this to work for any size signed int
    619     if (size == 1)
    620         val = Unserialize1SInt(pReader, pos);
    621     else
    622         val = Unserialize2SInt(pReader, pos);
    623 
    624     pos += size;  //consume size of payload
    625 
    626     return true;
    627 }
    628 
    629 
    630 namespace mkvparser
    631 {
    632 
    633 EBMLHeader::EBMLHeader():
    634     m_docType(NULL)
    635 {
    636 }
    637 
    638 EBMLHeader::~EBMLHeader()
    639 {
    640     delete[] m_docType;
    641 }
    642 
    643 long long EBMLHeader::Parse(
    644     IMkvReader* pReader,
    645     long long& pos)
    646 {
    647     assert(pReader);
    648 
    649     long long total, available;
    650 
    651     long hr = pReader->Length(&total, &available);
    652 
    653     if (hr < 0)
    654         return hr;
    655 
    656     pos = 0;
    657     long long end = (1024 < available)? 1024: available;
    658 
    659     for (;;)
    660     {
    661         unsigned char b = 0;
    662 
    663         while (pos < end)
    664         {
    665             hr = pReader->Read(pos, 1, &b);
    666 
    667             if (hr < 0)
    668                 return hr;
    669 
    670             if (b == 0x1A)
    671                 break;
    672 
    673             ++pos;
    674         }
    675 
    676         if (b != 0x1A)
    677         {
    678             if ((pos >= 1024) ||
    679                 (available >= total) ||
    680                 ((total - available) < 5))
    681                   return -1;
    682 
    683             return available + 5;  //5 = 4-byte ID + 1st byte of size
    684         }
    685 
    686         if ((total - pos) < 5)
    687             return E_FILE_FORMAT_INVALID;
    688 
    689         if ((available - pos) < 5)
    690             return pos + 5;  //try again later
    691 
    692         long len;
    693 
    694         const long long result = ReadUInt(pReader, pos, len);
    695 
    696         if (result < 0)  //error
    697             return result;
    698 
    699         if (result == 0x0A45DFA3)  //ReadId masks-off length indicator bits
    700         {
    701             assert(len == 4);
    702             pos += len;
    703             break;
    704         }
    705 
    706         ++pos;  //throw away just the 0x1A byte, and try again
    707     }
    708 
    709     long len;
    710     long long result = GetUIntLength(pReader, pos, len);
    711 
    712     if (result < 0)  //error
    713         return result;
    714 
    715     if (result > 0)  //need more data
    716         return result;
    717 
    718     assert(len > 0);
    719     assert(len <= 8);
    720 
    721     if ((total -  pos) < len)
    722         return E_FILE_FORMAT_INVALID;
    723     if ((available - pos) < len)
    724         return pos + len;  //try again later
    725 
    726     result = ReadUInt(pReader, pos, len);
    727 
    728     if (result < 0)  //error
    729         return result;
    730 
    731     pos += len;  //consume u-int
    732 
    733     if ((total - pos) < result)
    734         return E_FILE_FORMAT_INVALID;
    735 
    736     if ((available - pos) < result)
    737         return pos + result;
    738 
    739     end = pos + result;
    740 
    741     m_version = 1;
    742     m_readVersion = 1;
    743     m_maxIdLength = 4;
    744     m_maxSizeLength = 8;
    745     m_docTypeVersion = 1;
    746     m_docTypeReadVersion = 1;
    747 
    748     while (pos < end)
    749     {
    750         if (Match(pReader, pos, 0x0286, m_version))
    751             ;
    752         else if (Match(pReader, pos, 0x02F7, m_readVersion))
    753             ;
    754         else if (Match(pReader, pos, 0x02F2, m_maxIdLength))
    755             ;
    756         else if (Match(pReader, pos, 0x02F3, m_maxSizeLength))
    757             ;
    758         else if (Match(pReader, pos, 0x0282, m_docType))
    759             ;
    760         else if (Match(pReader, pos, 0x0287, m_docTypeVersion))
    761             ;
    762         else if (Match(pReader, pos, 0x0285, m_docTypeReadVersion))
    763             ;
    764         else
    765         {
    766             result = ReadUInt(pReader, pos, len);
    767             assert(result > 0);
    768             assert(len > 0);
    769             assert(len <= 8);
    770 
    771             pos += len;
    772             assert(pos < end);
    773 
    774             result = ReadUInt(pReader, pos, len);
    775             assert(result >= 0);
    776             assert(len > 0);
    777             assert(len <= 8);
    778 
    779             pos += len + result;
    780             assert(pos <= end);
    781         }
    782     }
    783 
    784     assert(pos == end);
    785 
    786     return 0;
    787 }
    788 
    789 
    790 Segment::Segment(
    791     IMkvReader* pReader,
    792     long long start,
    793     long long size) :
    794     m_pReader(pReader),
    795     m_start(start),
    796     m_size(size),
    797     m_pos(start),
    798     m_pInfo(NULL),
    799     m_pTracks(NULL),
    800     m_clusterCount(0)
    801     //m_clusterNumber(0)
    802 {
    803 }
    804 
    805 
    806 Segment::~Segment()
    807 {
    808     Cluster** i = m_clusters;
    809     Cluster** j = m_clusters + m_clusterCount;
    810 
    811     while (i != j)
    812     {
    813         Cluster* p = *i++;
    814         assert(p);
    815         delete p;
    816     }
    817 
    818     delete[] m_clusters;
    819 
    820     delete m_pTracks;
    821     delete m_pInfo;
    822 }
    823 
    824 
    825 long long Segment::CreateInstance(
    826     IMkvReader* pReader,
    827     long long pos,
    828     Segment*& pSegment)
    829 {
    830     assert(pReader);
    831     assert(pos >= 0);
    832 
    833     pSegment = NULL;
    834 
    835     long long total, available;
    836 
    837     long hr = pReader->Length(&total, &available);
    838     assert(hr >= 0);
    839     assert(available <= total);
    840 
    841     //I would assume that in practice this loop would execute
    842     //exactly once, but we allow for other elements (e.g. Void)
    843     //to immediately follow the EBML header.  This is fine for
    844     //the source filter case (since the entire file is available),
    845     //but in the splitter case over a network we should probably
    846     //just give up early.  We could for example decide only to
    847     //execute this loop a maximum of, say, 10 times.
    848 
    849     while (pos < total)
    850     {
    851         //Read ID
    852 
    853         long len;
    854         long long result = GetUIntLength(pReader, pos, len);
    855 
    856         if (result)  //error, or too few available bytes
    857             return result;
    858 
    859         if ((pos + len) > total)
    860             return E_FILE_FORMAT_INVALID;
    861 
    862         if ((pos + len) > available)
    863             return pos + len;
    864 
    865         //TODO: if we liberalize the behavior of ReadUInt, we can
    866         //probably eliminate having to use GetUIntLength here.
    867         const long long id = ReadUInt(pReader, pos, len);
    868 
    869         if (id < 0)  //error
    870             return id;
    871 
    872         pos += len;  //consume ID
    873 
    874         //Read Size
    875 
    876         result = GetUIntLength(pReader, pos, len);
    877 
    878         if (result)  //error, or too few available bytes
    879             return result;
    880 
    881         if ((pos + len) > total)
    882             return E_FILE_FORMAT_INVALID;
    883 
    884         if ((pos + len) > available)
    885             return pos + len;
    886 
    887         //TODO: if we liberalize the behavior of ReadUInt, we can
    888         //probably eliminate having to use GetUIntLength here.
    889         const long long size = ReadUInt(pReader, pos, len);
    890 
    891         if (size < 0)
    892             return size;
    893 
    894         pos += len;  //consume length of size of element
    895 
    896         //Pos now points to start of payload
    897 
    898         if ((pos + size) > total)
    899             return E_FILE_FORMAT_INVALID;
    900 
    901         if (id == 0x08538067)  //Segment ID
    902         {
    903             pSegment = new  Segment(pReader, pos, size);
    904             assert(pSegment);  //TODO
    905 
    906             return 0;    //success
    907         }
    908 
    909         pos += size;  //consume payload
    910     }
    911 
    912     assert(pos == total);
    913 
    914     pSegment = new Segment(pReader, pos, 0);
    915     assert(pSegment);  //TODO
    916 
    917     return 0;  //success (sort of)
    918 }
    919 
    920 
    921 long long Segment::ParseHeaders()
    922 {
    923     //Outermost (level 0) segment object has been constructed,
    924     //and pos designates start of payload.  We need to find the
    925     //inner (level 1) elements.
    926     long long total, available;
    927 
    928     long hr = m_pReader->Length(&total, &available);
    929     assert(hr >= 0);
    930     assert(available <= total);
    931 
    932     const long long stop = m_start + m_size;
    933     assert(stop <= total);
    934     assert(m_pos <= stop);
    935 
    936     bool bQuit = false;
    937     while ((m_pos < stop) && !bQuit)
    938     {
    939         long long pos = m_pos;
    940 
    941         long len;
    942         long long result = GetUIntLength(m_pReader, pos, len);
    943 
    944         if (result)  //error, or too few available bytes
    945             return result;
    946 
    947         if ((pos + len) > stop)
    948             return E_FILE_FORMAT_INVALID;
    949 
    950         if ((pos + len) > available)
    951             return pos + len;
    952 
    953         const long long idpos = pos;
    954         const long long id = ReadUInt(m_pReader, idpos, len);
    955 
    956         if (id < 0)  //error
    957             return id;
    958 
    959         pos += len;  //consume ID
    960 
    961         //Read Size
    962         result = GetUIntLength(m_pReader, pos, len);
    963 
    964         if (result)  //error, or too few available bytes
    965             return result;
    966 
    967         if ((pos + len) > stop)
    968             return E_FILE_FORMAT_INVALID;
    969 
    970         if ((pos + len) > available)
    971             return pos + len;
    972 
    973         const long long size = ReadUInt(m_pReader, pos, len);
    974 
    975         if (size < 0)
    976             return size;
    977 
    978         pos += len;  //consume length of size of element
    979 
    980         //Pos now points to start of payload
    981 
    982         if ((pos + size) > stop)
    983             return E_FILE_FORMAT_INVALID;
    984 
    985         //We read EBML elements either in total or nothing at all.
    986 
    987         if ((pos + size) > available)
    988             return pos + size;
    989 
    990         if (id == 0x0549A966)  //Segment Info ID
    991         {
    992             assert(m_pInfo == NULL);
    993             m_pInfo = new  SegmentInfo(this, pos, size);
    994             assert(m_pInfo);  //TODO
    995 
    996             if (m_pTracks)
    997                 bQuit = true;
    998         }
    999         else if (id == 0x0654AE6B)  //Tracks ID
   1000         {
   1001             assert(m_pTracks == NULL);
   1002             m_pTracks = new  Tracks(this, pos, size);
   1003             assert(m_pTracks);  //TODO
   1004 
   1005             if (m_pInfo)
   1006                 bQuit = true;
   1007         }
   1008         else if (id == 0x0F43B675)  //Cluster ID
   1009         {
   1010 #if 0
   1011             if (m_pInfo == NULL)  //TODO: liberalize
   1012                 ;
   1013             else if (m_pTracks == NULL)
   1014                 ;
   1015             else
   1016                 //ParseCluster(idpos, pos, size);
   1017                 Cluster::Parse(this, m_clusters, pos, size);
   1018 #endif
   1019             bQuit = true;
   1020         }
   1021 
   1022         m_pos = pos + size;  //consume payload
   1023     }
   1024 
   1025     assert(m_pos <= stop);
   1026 
   1027     return 0;  //success
   1028 }
   1029 
   1030 
   1031 long Segment::ParseCluster(Cluster*& pCluster, long long& pos_) const
   1032 {
   1033     pCluster = NULL;
   1034     pos_ = -1;
   1035 
   1036     const long long stop = m_start + m_size;
   1037     assert(m_pos <= stop);
   1038 
   1039     long long pos = m_pos;
   1040     long long off = -1;
   1041 
   1042 
   1043     while (pos < stop)
   1044     {
   1045         long len;
   1046         const long long idpos = pos;
   1047 
   1048         const long long id = SyncReadUInt(m_pReader, pos, stop, len);
   1049 
   1050         if (id < 0)  //error
   1051             return static_cast<long>(id);
   1052 
   1053         if (id == 0)
   1054             return E_FILE_FORMAT_INVALID;
   1055 
   1056         pos += len;  //consume id
   1057         assert(pos < stop);
   1058 
   1059         const long long size = SyncReadUInt(m_pReader, pos, stop, len);
   1060 
   1061         if (size < 0)  //error
   1062             return static_cast<long>(size);
   1063 
   1064         pos += len;  //consume size
   1065         assert(pos <= stop);
   1066 
   1067         if (size == 0)  //weird
   1068             continue;
   1069 
   1070         //pos now points to start of payload
   1071 
   1072         pos += size;  //consume payload
   1073         assert(pos <= stop);
   1074 
   1075         if (off >= 0)
   1076         {
   1077             pos_ = idpos;
   1078             break;
   1079         }
   1080 
   1081         if (id == 0x0F43B675)  //Cluster ID
   1082             off = idpos - m_start;
   1083     }
   1084 
   1085     Segment* const this_ = const_cast<Segment*>(this);
   1086     const size_t idx = m_clusterCount;
   1087 
   1088     if (pos >= stop)
   1089     {
   1090         pos_ = stop;
   1091 
   1092 #if 0
   1093         if (off < 0)
   1094         {
   1095             pCluster = Cluster::CreateEndOfStream(this_, idx);
   1096             return 1L;
   1097         }
   1098 #else
   1099         if (off < 0)
   1100             return 1L;
   1101 #endif
   1102 
   1103         //Reading 0 bytes at pos might work too -- it would depend
   1104         //on how the reader is implemented.
   1105 
   1106         unsigned char b;
   1107 
   1108         const long hr = m_pReader->Read(pos - 1, 1, &b);
   1109 
   1110         if (hr < 0)
   1111             return hr;
   1112 
   1113         if (hr != 0L)
   1114             return E_BUFFER_NOT_FULL;
   1115     }
   1116 
   1117     assert(off >= 0);
   1118     assert(pos_ >= m_start);
   1119     assert(pos_ <= stop);
   1120 
   1121     pCluster = Cluster::Parse(this_, idx, off);
   1122     return 0L;
   1123 }
   1124 
   1125 
   1126 bool Segment::AddCluster(Cluster* pCluster, long long pos)
   1127 {
   1128     assert(pos >= m_start);
   1129 
   1130     const long long stop = m_start + m_size;
   1131     assert(pos <= stop);
   1132 
   1133     if (pCluster)
   1134         m_clusters[pos] = pCluster;
   1135 
   1136     m_pos = pos;  //m_pos >= stop is now we know we have all clusters
   1137 
   1138     return (pos >= stop);
   1139 }
   1140 
   1141 
   1142 long Segment::Load()
   1143 {
   1144     //Outermost (level 0) segment object has been constructed,
   1145     //and pos designates start of payload.  We need to find the
   1146     //inner (level 1) elements.
   1147     const long long stop = m_start + m_size;
   1148 #ifdef _DEBUG
   1149     {
   1150         long long total, available;
   1151 
   1152         long hr = m_pReader->Length(&total, &available);
   1153         assert(hr >= 0);
   1154         assert(available >= total);
   1155         assert(stop <= total);
   1156     }
   1157 #endif
   1158     long long index = m_pos;
   1159 
   1160     m_clusterCount = 0;
   1161 
   1162     while (index < stop)
   1163     {
   1164         long len = 0;
   1165 
   1166         long long result = GetUIntLength(m_pReader, index, len);
   1167 
   1168         if (result < 0)  //error
   1169             return static_cast<long>(result);
   1170 
   1171         if ((index + len) > stop)
   1172             return E_FILE_FORMAT_INVALID;
   1173 
   1174         const long long idpos = index;
   1175         const long long id = ReadUInt(m_pReader, idpos, len);
   1176 
   1177         if (id < 0)  //error
   1178             return static_cast<long>(id);
   1179 
   1180         index += len;  //consume ID
   1181 
   1182         //Read Size
   1183         result = GetUIntLength(m_pReader, index, len);
   1184 
   1185         if (result < 0)  //error
   1186             return static_cast<long>(result);
   1187 
   1188         if ((index + len) > stop)
   1189             return E_FILE_FORMAT_INVALID;
   1190 
   1191         const long long size = ReadUInt(m_pReader, index, len);
   1192 
   1193         if (size < 0)  //error
   1194             return static_cast<long>(size);
   1195 
   1196         index += len;  //consume length of size of element
   1197 
   1198         if (id == 0x0F43B675) // Cluster ID
   1199             break;
   1200 
   1201         if (id == 0x014D9B74) // SeekHead ID
   1202         {
   1203             ParseSeekHead(index, size, NULL);
   1204             break;
   1205         }
   1206         index += size;
   1207     }
   1208 
   1209     if (m_clusterCount == 0)
   1210         return -1L;
   1211 
   1212     while (m_pos < stop)
   1213     {
   1214         long long pos = m_pos;
   1215 
   1216         long len;
   1217 
   1218         long long result = GetUIntLength(m_pReader, pos, len);
   1219 
   1220         if (result < 0)  //error
   1221             return static_cast<long>(result);
   1222 
   1223         if ((pos + len) > stop)
   1224             return E_FILE_FORMAT_INVALID;
   1225 
   1226         const long long idpos = pos;
   1227         const long long id = ReadUInt(m_pReader, idpos, len);
   1228 
   1229         if (id < 0)  //error
   1230             return static_cast<long>(id);
   1231 
   1232         pos += len;  //consume ID
   1233 
   1234         //Read Size
   1235         result = GetUIntLength(m_pReader, pos, len);
   1236 
   1237         if (result < 0)  //error
   1238             return static_cast<long>(result);
   1239 
   1240         if ((pos + len) > stop)
   1241 	        return E_FILE_FORMAT_INVALID;
   1242 
   1243         const long long size = ReadUInt(m_pReader, pos, len);
   1244 
   1245         if (size < 0)  //error
   1246             return static_cast<long>(size);
   1247 
   1248         pos += len;  //consume length of size of element
   1249 
   1250         //Pos now points to start of payload
   1251 
   1252         if ((pos + size) > stop)
   1253             return E_FILE_FORMAT_INVALID;
   1254 
   1255         if (id == 0x0F43B675)  //Cluster ID
   1256             break;
   1257 
   1258         if (id == 0x014D9B74)  //SeekHead ID
   1259         {
   1260             m_clusters = new Cluster*[m_clusterCount];
   1261             size_t index = 0;
   1262 
   1263             ParseSeekHead(pos, size, &index);
   1264             assert(index == m_clusterCount);
   1265         }
   1266         else if (id == 0x0549A966)  //Segment Info ID
   1267         {
   1268             assert(m_pInfo == NULL);
   1269             m_pInfo = new  SegmentInfo(this, pos, size);
   1270             assert(m_pInfo);  //TODO
   1271         }
   1272         else if (id == 0x0654AE6B)  //Tracks ID
   1273         {
   1274             assert(m_pTracks == NULL);
   1275             m_pTracks = new Tracks(this, pos, size);
   1276             assert(m_pTracks);  //TODO
   1277         }
   1278 
   1279         m_pos = pos + size;  //consume payload
   1280     }
   1281 
   1282     assert(m_clusters);
   1283 
   1284     //TODO: see notes above.  This check is here (temporarily) to ensure
   1285     //that the first seekhead has entries for the clusters (because that's
   1286     //when they're loaded).  In case we are given a file that lists the
   1287     //clusters in a second seekhead, the worst thing that happens is that
   1288     //we treat this as an invalid file (which is better then simply
   1289     //asserting somewhere).  But that's only a work-around.  What we need
   1290     //to do is be able to handle having multiple seekheads, and having
   1291     //clusters listed somewhere besides the first seekhead.
   1292     //
   1293     //if (m_clusters == NULL)
   1294     //    return E_FILE_FORMAT_INVALID;
   1295 
   1296     //NOTE: we stop parsing when we reach the first cluster, under the
   1297     //assumption all clusters are named in some SeekHead.  Clusters
   1298     //will have been (pre)loaded, so we indicate that we have all clusters
   1299     //by adjusting the parse position:
   1300     m_pos = stop;  //means "we have all clusters"
   1301 
   1302     return 0L;
   1303 }
   1304 
   1305 
   1306 void Segment::ParseSeekHead(long long start, long long size_, size_t* pIndex)
   1307 {
   1308     long long pos = start;
   1309     const long long stop = start + size_;
   1310     while (pos < stop)
   1311     {
   1312         long len;
   1313 
   1314         const long long id = ReadUInt(m_pReader, pos, len);
   1315         assert(id >= 0);  //TODO
   1316         assert((pos + len) <= stop);
   1317 
   1318         pos += len;  //consume ID
   1319 
   1320         const long long size = ReadUInt(m_pReader, pos, len);
   1321         assert(size >= 0);
   1322         assert((pos + len) <= stop);
   1323 
   1324         pos += len;  //consume Size field
   1325         assert((pos + size) <= stop);
   1326 
   1327         if (id == 0x0DBB)  //SeekEntry ID
   1328             ParseSeekEntry(pos, size, pIndex);
   1329 
   1330         pos += size;  //consume payload
   1331         assert(pos <= stop);
   1332     }
   1333 
   1334     assert(pos == stop);
   1335 }
   1336 
   1337 
   1338 void Segment::ParseSecondarySeekHead(long long off, size_t* pIndex)
   1339 {
   1340     assert(off >= 0);
   1341     assert(off < m_size);
   1342 
   1343     long long pos = m_start + off;
   1344     const long long stop = m_start + m_size;
   1345 
   1346     long len;
   1347 
   1348     long long result = GetUIntLength(m_pReader, pos, len);
   1349     assert(result == 0);
   1350     assert((pos + len) <= stop);
   1351 
   1352     const long long idpos = pos;
   1353 
   1354     const long long id = ReadUInt(m_pReader, idpos, len);
   1355     assert(id == 0x014D9B74);  //SeekHead ID
   1356 
   1357     pos += len;  //consume ID
   1358     assert(pos < stop);
   1359 
   1360     //Read Size
   1361 
   1362     result = GetUIntLength(m_pReader, pos, len);
   1363     assert(result == 0);
   1364     assert((pos + len) <= stop);
   1365 
   1366     const long long size = ReadUInt(m_pReader, pos, len);
   1367     assert(size >= 0);
   1368 
   1369     pos += len;  //consume length of size of element
   1370     assert((pos + size) <= stop);
   1371 
   1372     //Pos now points to start of payload
   1373 
   1374     ParseSeekHead(pos, size, pIndex);
   1375 }
   1376 
   1377 
   1378 void Segment::ParseSeekEntry(long long start, long long size_, size_t* pIndex)
   1379 {
   1380     long long pos = start;
   1381 
   1382     const long long stop = start + size_;
   1383 
   1384     long len;
   1385 
   1386     const long long seekIdId = ReadUInt(m_pReader, pos, len);
   1387     //seekIdId;
   1388     assert(seekIdId == 0x13AB);  //SeekID ID
   1389     assert((pos + len) <= stop);
   1390 
   1391     pos += len;  //consume id
   1392 
   1393     const long long seekIdSize = ReadUInt(m_pReader, pos, len);
   1394     assert(seekIdSize >= 0);
   1395     assert((pos + len) <= stop);
   1396 
   1397     pos += len;  //consume size
   1398 
   1399     const long long seekId = ReadUInt(m_pReader, pos, len);  //payload
   1400     assert(seekId >= 0);
   1401     assert(len == seekIdSize);
   1402     assert((pos + len) <= stop);
   1403 
   1404     pos += seekIdSize;  //consume payload
   1405 
   1406     const long long seekPosId = ReadUInt(m_pReader, pos, len);
   1407     //seekPosId;
   1408     assert(seekPosId == 0x13AC);  //SeekPos ID
   1409     assert((pos + len) <= stop);
   1410 
   1411     pos += len;  //consume id
   1412 
   1413     const long long seekPosSize = ReadUInt(m_pReader, pos, len);
   1414     assert(seekPosSize >= 0);
   1415     assert((pos + len) <= stop);
   1416 
   1417     pos += len;  //consume size
   1418     assert((pos + seekPosSize) <= stop);
   1419 
   1420     const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize);
   1421     assert(seekOff >= 0);
   1422     assert(seekOff < m_size);
   1423 
   1424     pos += seekPosSize;  //consume payload
   1425     assert(pos == stop);
   1426 
   1427     const long long seekPos = m_start + seekOff;
   1428     assert(seekPos < (m_start + m_size));
   1429 
   1430     if (seekId == 0x0F43B675)  //cluster id
   1431     {
   1432         if (pIndex == NULL)
   1433             ++m_clusterCount;
   1434         else
   1435         {
   1436             assert(m_clusters);
   1437             assert(m_clusterCount > 0);
   1438 
   1439             size_t& index = *pIndex;
   1440             assert(index < m_clusterCount);
   1441 
   1442             Cluster*& pCluster = m_clusters[index];
   1443 
   1444             pCluster = Cluster::Parse(this, index, seekOff);
   1445             assert(pCluster);  //TODO
   1446 
   1447             ++index;
   1448         }
   1449     }
   1450     else if (seekId == 0x014D9B74)  //SeekHead ID
   1451     {
   1452         ParseSecondarySeekHead(seekOff, pIndex);
   1453     }
   1454 }
   1455 
   1456 
   1457 long long Segment::Unparsed() const
   1458 {
   1459     const long long stop = m_start + m_size;
   1460 
   1461     const long long result = stop - m_pos;
   1462     assert(result >= 0);
   1463 
   1464     return result;
   1465 }
   1466 
   1467 
   1468 #if 0  //NOTE: too inefficient
   1469 long long Segment::Load(long long time_ns)
   1470 {
   1471     if (Unparsed() <= 0)
   1472         return 0;
   1473 
   1474     while (m_clusters.empty())
   1475     {
   1476         const long long result = Parse();
   1477 
   1478         if (result)  //error, or not enough bytes available
   1479             return result;
   1480 
   1481         if (Unparsed() <= 0)
   1482             return 0;
   1483     }
   1484 
   1485     while (m_clusters.back()->GetTime() < time_ns)
   1486     {
   1487         const long long result = Parse();
   1488 
   1489         if (result)  //error, or not enough bytes available
   1490             return result;
   1491 
   1492         if (Unparsed() <= 0)
   1493             return 0;
   1494     }
   1495 
   1496     return 0;
   1497 }
   1498 #endif
   1499 
   1500 
   1501 Cluster* Segment::GetFirst()
   1502 {
   1503     if ((m_clusters == NULL) || (m_clusterCount <= 0))
   1504        return &m_eos;
   1505 
   1506     Cluster* const pCluster = m_clusters[0];
   1507     assert(pCluster);
   1508 
   1509     return pCluster;
   1510 }
   1511 
   1512 
   1513 Cluster* Segment::GetLast()
   1514 {
   1515     if ((m_clusters == NULL) || (m_clusterCount <= 0))
   1516         return &m_eos;
   1517 
   1518     const size_t idx = m_clusterCount - 1;
   1519     Cluster* const pCluster = m_clusters[idx];
   1520     assert(pCluster);
   1521 
   1522     return pCluster;
   1523 }
   1524 
   1525 
   1526 unsigned long Segment::GetCount() const
   1527 {
   1528     //TODO: m_clusterCount should not be long long.
   1529     return static_cast<unsigned long>(m_clusterCount);
   1530 }
   1531 
   1532 
   1533 Cluster* Segment::GetNext(const Cluster* pCurr)
   1534 {
   1535     assert(pCurr);
   1536     assert(pCurr != &m_eos);
   1537     assert(m_clusters);
   1538     assert(m_clusterCount > 0);
   1539 
   1540     size_t idx =  pCurr->m_index;
   1541     assert(idx < m_clusterCount);
   1542     assert(pCurr == m_clusters[idx]);
   1543 
   1544     idx++;
   1545 
   1546     if (idx >= m_clusterCount)
   1547         return &m_eos;
   1548 
   1549     Cluster* const pNext = m_clusters[idx];
   1550     assert(pNext);
   1551 
   1552     return pNext;
   1553 }
   1554 
   1555 
   1556 Cluster* Segment::GetCluster(long long time_ns)
   1557 {
   1558     if ((m_clusters == NULL) || (m_clusterCount <= 0))
   1559         return &m_eos;
   1560 
   1561     {
   1562         Cluster* const pCluster = m_clusters[0];
   1563         assert(pCluster);
   1564         assert(pCluster->m_index == 0);
   1565 
   1566         if (time_ns <= pCluster->GetTime())
   1567             return pCluster;
   1568     }
   1569 
   1570     //Binary search of cluster array
   1571 
   1572     size_t i = 0;
   1573     size_t j = m_clusterCount;
   1574 
   1575     while (i < j)
   1576     {
   1577         //INVARIANT:
   1578         //[0, i) <= time_ns
   1579         //[i, j) ?
   1580         //[j, m_clusterCount)  > time_ns
   1581 
   1582         const size_t k = i + (j - i) / 2;
   1583         assert(k < m_clusterCount);
   1584 
   1585         Cluster* const pCluster = m_clusters[k];
   1586         assert(pCluster);
   1587         assert(pCluster->m_index == k);
   1588 
   1589         const long long t = pCluster->GetTime();
   1590 
   1591         if (t <= time_ns)
   1592             i = k + 1;
   1593         else
   1594             j = k;
   1595 
   1596         assert(i <= j);
   1597     }
   1598 
   1599     assert(i == j);
   1600     assert(i > 0);
   1601     assert(i <= m_clusterCount);
   1602 
   1603     const size_t k = i - 1;
   1604 
   1605     Cluster* const pCluster = m_clusters[k];
   1606     assert(pCluster);
   1607     assert(pCluster->m_index == k);
   1608     assert(pCluster->GetTime() <= time_ns);
   1609 
   1610     return pCluster;
   1611 }
   1612 
   1613 
   1614 Tracks* Segment::GetTracks() const
   1615 {
   1616     return m_pTracks;
   1617 }
   1618 
   1619 
   1620 const SegmentInfo* const Segment::GetInfo() const
   1621 {
   1622     return m_pInfo;
   1623 }
   1624 
   1625 
   1626 long long Segment::GetDuration() const
   1627 {
   1628     assert(m_pInfo);
   1629     return m_pInfo->GetDuration();
   1630 }
   1631 
   1632 
   1633 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_) :
   1634     m_pSegment(pSegment),
   1635     m_start(start),
   1636     m_size(size_),
   1637     m_pMuxingAppAsUTF8(NULL),
   1638     m_pWritingAppAsUTF8(NULL),
   1639     m_pTitleAsUTF8(NULL)
   1640 {
   1641     IMkvReader* const pReader = m_pSegment->m_pReader;
   1642 
   1643     long long pos = start;
   1644     const long long stop = start + size_;
   1645 
   1646     m_timecodeScale = 1000000;
   1647     m_duration = 0;
   1648 
   1649 
   1650     while (pos < stop)
   1651     {
   1652         if (Match(pReader, pos, 0x0AD7B1, m_timecodeScale))
   1653             assert(m_timecodeScale > 0);
   1654 
   1655         else if (Match(pReader, pos, 0x0489, m_duration))
   1656             assert(m_duration >= 0);
   1657 
   1658         else if (Match(pReader, pos, 0x0D80, m_pMuxingAppAsUTF8))   //[4D][80]
   1659             assert(m_pMuxingAppAsUTF8);
   1660 
   1661         else if (Match(pReader, pos, 0x1741, m_pWritingAppAsUTF8))  //[57][41]
   1662             assert(m_pWritingAppAsUTF8);
   1663 
   1664         else if (Match(pReader, pos, 0x3BA9, m_pTitleAsUTF8))        //[7B][A9]
   1665             assert(m_pTitleAsUTF8);
   1666 
   1667         else
   1668         {
   1669             long len;
   1670 
   1671             const long long id = ReadUInt(pReader, pos, len);
   1672             //id;
   1673             assert(id >= 0);
   1674             assert((pos + len) <= stop);
   1675 
   1676             pos += len;  //consume id
   1677             assert((stop - pos) > 0);
   1678 
   1679             const long long size = ReadUInt(pReader, pos, len);
   1680             assert(size >= 0);
   1681             assert((pos + len) <= stop);
   1682 
   1683             pos += len + size;  //consume size and payload
   1684             assert(pos <= stop);
   1685         }
   1686     }
   1687 
   1688     assert(pos == stop);
   1689 }
   1690 
   1691 SegmentInfo::~SegmentInfo()
   1692 {
   1693     if (m_pMuxingAppAsUTF8)
   1694     {
   1695         delete[] m_pMuxingAppAsUTF8;
   1696         m_pMuxingAppAsUTF8 = NULL;
   1697     }
   1698 
   1699     if (m_pWritingAppAsUTF8)
   1700     {
   1701         delete[] m_pWritingAppAsUTF8;
   1702         m_pWritingAppAsUTF8 = NULL;
   1703     }
   1704 
   1705     if (m_pTitleAsUTF8)
   1706     {
   1707         delete[] m_pTitleAsUTF8;
   1708         m_pTitleAsUTF8 = NULL;
   1709     }
   1710 }
   1711 
   1712 long long SegmentInfo::GetTimeCodeScale() const
   1713 {
   1714     return m_timecodeScale;
   1715 }
   1716 
   1717 
   1718 long long SegmentInfo::GetDuration() const
   1719 {
   1720     assert(m_duration >= 0);
   1721     assert(m_timecodeScale >= 1);
   1722 
   1723     const double dd = double(m_duration) * double(m_timecodeScale);
   1724     const long long d = static_cast<long long>(dd);
   1725 
   1726     return d;
   1727 }
   1728 
   1729 const char* SegmentInfo::GetMuxingAppAsUTF8() const
   1730 {
   1731     return m_pMuxingAppAsUTF8;
   1732 }
   1733 
   1734 const char* SegmentInfo::GetWritingAppAsUTF8() const
   1735 {
   1736     return m_pWritingAppAsUTF8;
   1737 }
   1738 
   1739 const char* SegmentInfo::GetTitleAsUTF8() const
   1740 {
   1741     return m_pTitleAsUTF8;
   1742 }
   1743 
   1744 Track::Track(Segment* pSegment, const Info& i) :
   1745     m_pSegment(pSegment),
   1746     m_info(i)
   1747 {
   1748 }
   1749 
   1750 Track::~Track()
   1751 {
   1752     Info& info = const_cast<Info&>(m_info);
   1753     info.Clear();
   1754 }
   1755 
   1756 Track::Info::Info():
   1757     type(-1),
   1758     number(-1),
   1759     uid(-1),
   1760     nameAsUTF8(NULL),
   1761     codecId(NULL),
   1762     codecPrivate(NULL),
   1763     codecPrivateSize(0),
   1764     codecNameAsUTF8(NULL)
   1765 {
   1766 }
   1767 
   1768 void Track::Info::Clear()
   1769 {
   1770     delete[] nameAsUTF8;
   1771     nameAsUTF8 = NULL;
   1772 
   1773     delete[] codecId;
   1774     codecId = NULL;
   1775 
   1776     delete[] codecPrivate;
   1777     codecPrivate = NULL;
   1778 
   1779     delete[] codecNameAsUTF8;
   1780     codecNameAsUTF8 = NULL;
   1781 }
   1782 
   1783 const BlockEntry* Track::GetEOS() const
   1784 {
   1785     return &m_eos;
   1786 }
   1787 
   1788 long long Track::GetType() const
   1789 {
   1790     const unsigned long result = static_cast<unsigned long>(m_info.type);
   1791     return result;
   1792 }
   1793 
   1794 unsigned long Track::GetNumber() const
   1795 {
   1796     assert(m_info.number >= 0);
   1797     const unsigned long result = static_cast<unsigned long>(m_info.number);
   1798     return result;
   1799 }
   1800 
   1801 const char* Track::GetNameAsUTF8() const
   1802 {
   1803     return m_info.nameAsUTF8;
   1804 }
   1805 
   1806 const char* Track::GetCodecNameAsUTF8() const
   1807 {
   1808     return m_info.codecNameAsUTF8;
   1809 }
   1810 
   1811 
   1812 const char* Track::GetCodecId() const
   1813 {
   1814     return m_info.codecId;
   1815 }
   1816 
   1817 
   1818 const unsigned char* Track::GetCodecPrivate(size_t *optionalSize) const
   1819 {
   1820     if (optionalSize) {
   1821         *optionalSize = m_info.codecPrivateSize;
   1822     }
   1823     return m_info.codecPrivate;
   1824 }
   1825 
   1826 
   1827 long Track::GetFirst(const BlockEntry*& pBlockEntry) const
   1828 {
   1829     Cluster* const pCluster = m_pSegment->GetFirst();
   1830 
   1831     //If Segment::GetFirst returns NULL, then this must be a network
   1832     //download, and we haven't loaded any clusters yet.  In this case,
   1833     //returning NULL from Track::GetFirst means the same thing.
   1834 
   1835     if ((pCluster == NULL) || pCluster->EOS())
   1836     {
   1837         pBlockEntry = NULL;
   1838         return E_BUFFER_NOT_FULL;  //return 1L instead?
   1839     }
   1840 
   1841     pBlockEntry = pCluster->GetFirst();
   1842 
   1843     while (pBlockEntry)
   1844     {
   1845         const Block* const pBlock = pBlockEntry->GetBlock();
   1846         assert(pBlock);
   1847 
   1848         if (pBlock->GetTrackNumber() == (unsigned long)m_info.number)
   1849             return 0L;
   1850 
   1851         pBlockEntry = pCluster->GetNext(pBlockEntry);
   1852     }
   1853 
   1854     //NOTE: if we get here, it means that we didn't find a block with
   1855     //a matching track number.  We interpret that as an error (which
   1856     //might be too conservative).
   1857 
   1858     pBlockEntry = GetEOS();  //so we can return a non-NULL value
   1859     return 1L;
   1860 }
   1861 
   1862 
   1863 long Track::GetNext(const BlockEntry* pCurrEntry, const BlockEntry*& pNextEntry) const
   1864 {
   1865     assert(pCurrEntry);
   1866     assert(!pCurrEntry->EOS());  //?
   1867     assert(pCurrEntry->GetBlock()->GetTrackNumber() == (unsigned long)m_info.number);
   1868 
   1869     const Cluster* const pCurrCluster = pCurrEntry->GetCluster();
   1870     assert(pCurrCluster);
   1871     assert(!pCurrCluster->EOS());
   1872 
   1873     pNextEntry = pCurrCluster->GetNext(pCurrEntry);
   1874 
   1875     while (pNextEntry)
   1876     {
   1877         const Block* const pNextBlock = pNextEntry->GetBlock();
   1878         assert(pNextBlock);
   1879 
   1880         if (pNextBlock->GetTrackNumber() == (unsigned long)m_info.number)
   1881             return 0L;
   1882 
   1883         pNextEntry = pCurrCluster->GetNext(pNextEntry);
   1884     }
   1885 
   1886     Segment* pSegment = pCurrCluster->m_pSegment;
   1887     Cluster* const pNextCluster = pSegment->GetNext(pCurrCluster);
   1888 
   1889     if ((pNextCluster == NULL) || pNextCluster->EOS())
   1890     {
   1891         if (pSegment->Unparsed() <= 0)   //all clusters have been loaded
   1892         {
   1893             pNextEntry = GetEOS();
   1894             return 1L;
   1895         }
   1896 
   1897         pNextEntry = NULL;
   1898         return E_BUFFER_NOT_FULL;
   1899     }
   1900 
   1901     pNextEntry = pNextCluster->GetFirst();
   1902 
   1903     while (pNextEntry)
   1904     {
   1905         const Block* const pNextBlock = pNextEntry->GetBlock();
   1906         assert(pNextBlock);
   1907 
   1908         if (pNextBlock->GetTrackNumber() == (unsigned long)m_info.number)
   1909             return 0L;
   1910 
   1911         pNextEntry = pNextCluster->GetNext(pNextEntry);
   1912     }
   1913 
   1914     //TODO: what has happened here is that we did not find a block
   1915     //with a matching track number on the next cluster.  It might
   1916     //be the case that some cluster beyond the next cluster
   1917     //contains a block having a matching track number, but for
   1918     //now we terminate the search immediately.  We do this so that
   1919     //we don't end up searching the entire file looking for the
   1920     //next block.  Another possibility is to try searching for the next
   1921     //block in a small, fixed number of clusters (intead searching
   1922     //just the next one), or to terminate the search when when the
   1923     //there is a large gap in time, or large gap in file position.  It
   1924     //might very well be the case that the approach we use here is
   1925     //unnecessarily conservative.
   1926 
   1927     //TODO: again, here's a case where we need to return the special
   1928     //EOS block.  Or something.  It's OK if pNext is NULL, because
   1929     //we only need it to set the stop time of the media sample.
   1930     //(The start time is determined from pCurr, which is non-NULL
   1931     //and non-EOS.)  The problem is when we set pCurr=pNext; when
   1932     //pCurr has the value NULL we interpret that to mean that we
   1933     //haven't fully initialized pCurr and we attempt to set it to
   1934     //point to the first block for this track.  But that's not what
   1935     //we want at all; we want the next call to PopulateSample to
   1936     //return end-of-stream, not (re)start from the beginning.
   1937     //
   1938     //One work-around is to send EOS immediately.  We would send
   1939     //the EOS the next pass anyway, so maybe it's no great loss.  The
   1940     //only problem is that if this the stream really does end one
   1941     //cluster early (relative to other tracks), or the last frame
   1942     //happens to be a keyframe ("CanSeekToEnd").
   1943     //
   1944     //The problem is that we need a way to mark as stream as
   1945     //"at end of stream" without actually being at end of stream.
   1946     //We need to give pCurr some value that means "you've reached EOS".
   1947     //We can't synthesize the special EOS Cluster immediately
   1948     //(when we first open the file, say), because we use the existance
   1949     //of that special cluster value to mean that we've read all of
   1950     //the clusters (this is a network download, so we can't know apriori
   1951     //how many we have).
   1952     //
   1953     //Or, we could return E_FAIL, and set another bit in the stream
   1954     //object itself, to indicate that it should send EOS earlier
   1955     //than when (pCurr=pStop).
   1956     //
   1957     //Or, probably the best solution, when we actually load the
   1958     //blocks into a cluster: if we notice that there's no block
   1959     //for a track, we synthesize a nonce EOS block for that track.
   1960     //That way we always have something to return.  But that will
   1961     //only work for sequential scan???
   1962 
   1963     //pNext = NULL;
   1964     //return E_FAIL;
   1965     pNextEntry = GetEOS();
   1966     return 1L;
   1967 }
   1968 
   1969 
   1970 Track::EOSBlock::EOSBlock()
   1971 {
   1972 }
   1973 
   1974 
   1975 bool Track::EOSBlock::EOS() const
   1976 {
   1977     return true;
   1978 }
   1979 
   1980 
   1981 Cluster* Track::EOSBlock::GetCluster() const
   1982 {
   1983     return NULL;
   1984 }
   1985 
   1986 
   1987 size_t Track::EOSBlock::GetIndex() const
   1988 {
   1989     return 0;
   1990 }
   1991 
   1992 
   1993 const Block* Track::EOSBlock::GetBlock() const
   1994 {
   1995     return NULL;
   1996 }
   1997 
   1998 
   1999 bool Track::EOSBlock::IsBFrame() const
   2000 {
   2001     return false;
   2002 }
   2003 
   2004 
   2005 VideoTrack::VideoTrack(Segment* pSegment, const Info& i) :
   2006     Track(pSegment, i),
   2007     m_width(-1),
   2008     m_height(-1),
   2009     m_rate(-1)
   2010 {
   2011     assert(i.type == 1);
   2012     assert(i.number > 0);
   2013 
   2014     IMkvReader* const pReader = pSegment->m_pReader;
   2015 
   2016     const Settings& s = i.settings;
   2017     assert(s.start >= 0);
   2018     assert(s.size >= 0);
   2019 
   2020     long long pos = s.start;
   2021     assert(pos >= 0);
   2022 
   2023     const long long stop = pos + s.size;
   2024 
   2025     while (pos < stop)
   2026     {
   2027 #ifdef _DEBUG
   2028         long len;
   2029         const long long id = ReadUInt(pReader, pos, len);
   2030         assert(id >= 0);  //TODO: handle error case
   2031         assert((pos + len) <= stop);
   2032 #endif
   2033         if (Match(pReader, pos, 0x30, m_width))
   2034             ;
   2035         else if (Match(pReader, pos, 0x3A, m_height))
   2036             ;
   2037         else if (Match(pReader, pos, 0x0383E3, m_rate))
   2038             ;
   2039         else
   2040         {
   2041             long len;
   2042             const long long id = ReadUInt(pReader, pos, len);
   2043             assert(id >= 0);  //TODO: handle error case
   2044             assert((pos + len) <= stop);
   2045 
   2046             pos += len;  //consume id
   2047 
   2048             const long long size = ReadUInt(pReader, pos, len);
   2049             assert(size >= 0);  //TODO: handle error case
   2050             assert((pos + len) <= stop);
   2051 
   2052             pos += len;  //consume length of size
   2053             assert((pos + size) <= stop);
   2054 
   2055             //pos now designates start of payload
   2056 
   2057             pos += size;  //consume payload
   2058             assert(pos <= stop);
   2059         }
   2060     }
   2061 
   2062     return;
   2063 }
   2064 
   2065 
   2066 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const
   2067 {
   2068     assert(pBlockEntry);
   2069 
   2070     const Block* const pBlock = pBlockEntry->GetBlock();
   2071     assert(pBlock);
   2072     assert(pBlock->GetTrackNumber() == (unsigned long)m_info.number);
   2073 
   2074     return pBlock->IsKey();
   2075 }
   2076 
   2077 
   2078 
   2079 long long VideoTrack::GetWidth() const
   2080 {
   2081     return m_width;
   2082 }
   2083 
   2084 
   2085 long long VideoTrack::GetHeight() const
   2086 {
   2087     return m_height;
   2088 }
   2089 
   2090 
   2091 double VideoTrack::GetFrameRate() const
   2092 {
   2093     return m_rate;
   2094 }
   2095 
   2096 
   2097 AudioTrack::AudioTrack(Segment* pSegment, const Info& i) :
   2098     Track(pSegment, i)
   2099 {
   2100     assert(i.type == 2);
   2101     assert(i.number > 0);
   2102 
   2103     IMkvReader* const pReader = pSegment->m_pReader;
   2104 
   2105     const Settings& s = i.settings;
   2106     assert(s.start >= 0);
   2107     assert(s.size >= 0);
   2108 
   2109     long long pos = s.start;
   2110     assert(pos >= 0);
   2111 
   2112     const long long stop = pos + s.size;
   2113 
   2114     while (pos < stop)
   2115     {
   2116 #ifdef _DEBUG
   2117         long len;
   2118         const long long id = ReadUInt(pReader, pos, len);
   2119         assert(id >= 0);  //TODO: handle error case
   2120         assert((pos + len) <= stop);
   2121 #endif
   2122         if (Match(pReader, pos, 0x35, m_rate))
   2123             ;
   2124         else if (Match(pReader, pos, 0x1F, m_channels))
   2125             ;
   2126         else if (Match(pReader, pos, 0x2264, m_bitDepth))
   2127             ;
   2128         else
   2129         {
   2130             long len;
   2131             const long long id = ReadUInt(pReader, pos, len);
   2132             assert(id >= 0);  //TODO: handle error case
   2133             assert((pos + len) <= stop);
   2134 
   2135             pos += len;  //consume id
   2136 
   2137             const long long size = ReadUInt(pReader, pos, len);
   2138             assert(size >= 0);  //TODO: handle error case
   2139             assert((pos + len) <= stop);
   2140 
   2141             pos += len;  //consume length of size
   2142             assert((pos + size) <= stop);
   2143 
   2144             //pos now designates start of payload
   2145 
   2146             pos += size;  //consume payload
   2147             assert(pos <= stop);
   2148         }
   2149     }
   2150 
   2151     return;
   2152 }
   2153 
   2154 bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const
   2155 {
   2156     assert(pBlockEntry);
   2157 
   2158     const Block* const pBlock = pBlockEntry->GetBlock();
   2159     assert(pBlock);
   2160     assert(pBlock->GetTrackNumber() == (unsigned long)m_info.number);
   2161 
   2162     return true;
   2163 }
   2164 
   2165 
   2166 double AudioTrack::GetSamplingRate() const
   2167 {
   2168     return m_rate;
   2169 }
   2170 
   2171 
   2172 long long AudioTrack::GetChannels() const
   2173 {
   2174     return m_channels;
   2175 }
   2176 
   2177 long long AudioTrack::GetBitDepth() const
   2178 {
   2179     return m_bitDepth;
   2180 }
   2181 
   2182 Tracks::Tracks(Segment* pSegment, long long start, long long size_) :
   2183     m_pSegment(pSegment),
   2184     m_start(start),
   2185     m_size(size_),
   2186     m_trackEntries(NULL),
   2187     m_trackEntriesEnd(NULL)
   2188 {
   2189     long long stop = m_start + m_size;
   2190     IMkvReader* const pReader = m_pSegment->m_pReader;
   2191 
   2192     long long pos1 = m_start;
   2193     int count = 0;
   2194 
   2195     while (pos1 < stop)
   2196     {
   2197         long len;
   2198         const long long id = ReadUInt(pReader, pos1, len);
   2199         assert(id >= 0);
   2200         assert((pos1 + len) <= stop);
   2201 
   2202         pos1 += len;  //consume id
   2203 
   2204         const long long size = ReadUInt(pReader, pos1, len);
   2205         assert(size >= 0);
   2206         assert((pos1 + len) <= stop);
   2207 
   2208         pos1 += len;  //consume length of size
   2209 
   2210         //pos now desinates start of element
   2211         if (id == 0x2E)  //TrackEntry ID
   2212             ++count;
   2213 
   2214         pos1 += size;  //consume payload
   2215         assert(pos1 <= stop);
   2216     }
   2217 
   2218     if (count <= 0)
   2219         return;
   2220 
   2221     m_trackEntries = new Track*[count];
   2222     m_trackEntriesEnd = m_trackEntries;
   2223 
   2224     long long pos = m_start;
   2225 
   2226     while (pos < stop)
   2227     {
   2228         long len;
   2229         const long long id = ReadUInt(pReader, pos, len);
   2230         assert(id >= 0);
   2231         assert((pos + len) <= stop);
   2232 
   2233         pos += len;  //consume id
   2234 
   2235         const long long size1 = ReadUInt(pReader, pos, len);
   2236         assert(size1 >= 0);
   2237         assert((pos + len) <= stop);
   2238 
   2239         pos += len;  //consume length of size
   2240 
   2241         //pos now desinates start of element
   2242 
   2243         if (id == 0x2E)  //TrackEntry ID
   2244             ParseTrackEntry(pos, size1, *m_trackEntriesEnd++);
   2245 
   2246         pos += size1;  //consume payload
   2247         assert(pos <= stop);
   2248     }
   2249 }
   2250 
   2251 unsigned long Tracks::GetTracksCount() const
   2252 {
   2253     const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
   2254     assert(result >= 0);
   2255 
   2256     return static_cast<unsigned long>(result);
   2257 }
   2258 
   2259 
   2260 void Tracks::ParseTrackEntry(
   2261     long long start,
   2262     long long size,
   2263     Track*& pTrack)
   2264 {
   2265     IMkvReader* const pReader = m_pSegment->m_pReader;
   2266 
   2267     long long pos = start;
   2268     const long long stop = start + size;
   2269 
   2270     Track::Info i;
   2271 
   2272     Track::Settings videoSettings;
   2273     videoSettings.start = -1;
   2274 
   2275     Track::Settings audioSettings;
   2276     audioSettings.start = -1;
   2277 
   2278     while (pos < stop)
   2279     {
   2280 #ifdef _DEBUG
   2281         long len;
   2282         const long long id = ReadUInt(pReader, pos, len);
   2283         len;
   2284         id;
   2285 #endif
   2286         if (Match(pReader, pos, 0x57, i.number))
   2287             assert(i.number > 0);
   2288 
   2289         else if (Match(pReader, pos, 0x33C5, i.uid))
   2290             ;
   2291 
   2292         else if (Match(pReader, pos, 0x03, i.type))
   2293             ;
   2294 
   2295         else if (Match(pReader, pos, 0x136E, i.nameAsUTF8))
   2296             assert(i.nameAsUTF8);
   2297 
   2298         else if (Match(pReader, pos, 0x06, i.codecId))
   2299             ;
   2300 
   2301         else if (Match(pReader, pos, 0x23A2, i.codecPrivate, &i.codecPrivateSize))
   2302             ;
   2303 
   2304         else if (Match(pReader, pos, 0x058688, i.codecNameAsUTF8))
   2305             assert(i.codecNameAsUTF8);
   2306 
   2307         else
   2308         {
   2309             long len;
   2310 
   2311             const long long id = ReadUInt(pReader, pos, len);
   2312             assert(id >= 0);  //TODO: handle error case
   2313             assert((pos + len) <= stop);
   2314 
   2315             pos += len;  //consume id
   2316 
   2317             const long long size = ReadUInt(pReader, pos, len);
   2318             assert(size >= 0);  //TODO: handle error case
   2319             assert((pos + len) <= stop);
   2320 
   2321             pos += len;  //consume length of size
   2322             const long long start = pos;
   2323 
   2324             pos += size;  //consume payload
   2325             assert(pos <= stop);
   2326 
   2327             if (id == 0x60)
   2328             {
   2329                 videoSettings.start = start;
   2330                 videoSettings.size = size;
   2331             }
   2332             else if (id == 0x61)
   2333             {
   2334                 audioSettings.start = start;
   2335                 audioSettings.size = size;
   2336             }
   2337         }
   2338     }
   2339 
   2340     assert(pos == stop);
   2341     //TODO: propertly vet info.number, to ensure both its existence,
   2342     //and that it is unique among all tracks.
   2343     assert(i.number > 0);
   2344 
   2345     //TODO: vet settings, to ensure that video settings (0x60)
   2346     //were specified when type = 1, and that audio settings (0x61)
   2347     //were specified when type = 2.
   2348     if (i.type == 1)  //video
   2349     {
   2350         assert(audioSettings.start < 0);
   2351         assert(videoSettings.start >= 0);
   2352 
   2353         i.settings = videoSettings;
   2354 
   2355         VideoTrack* const t = new VideoTrack(m_pSegment, i);
   2356         assert(t);  //TODO
   2357         pTrack = t;
   2358     }
   2359     else if (i.type == 2)  //audio
   2360     {
   2361         assert(videoSettings.start < 0);
   2362         assert(audioSettings.start >= 0);
   2363 
   2364         i.settings = audioSettings;
   2365 
   2366         AudioTrack* const t = new  AudioTrack(m_pSegment, i);
   2367         assert(t);  //TODO
   2368         pTrack = t;
   2369     }
   2370     else
   2371     {
   2372         // for now we do not support other track types yet.
   2373         // TODO: support other track types
   2374         i.Clear();
   2375 
   2376         pTrack = NULL;
   2377     }
   2378 
   2379     return;
   2380 }
   2381 
   2382 
   2383 Tracks::~Tracks()
   2384 {
   2385     Track** i = m_trackEntries;
   2386     Track** const j = m_trackEntriesEnd;
   2387 
   2388     while (i != j)
   2389     {
   2390         Track* pTrack = *i++;
   2391         delete pTrack;
   2392         pTrack = NULL;
   2393     }
   2394 
   2395     delete[] m_trackEntries;
   2396 }
   2397 
   2398 
   2399 Track* Tracks::GetTrackByNumber(unsigned long tn) const
   2400 {
   2401     Track** i = m_trackEntries;
   2402     Track** const j = m_trackEntriesEnd;
   2403 
   2404     while (i != j)
   2405     {
   2406         Track* const pTrack = *i++;
   2407 
   2408         if (pTrack == NULL)
   2409             continue;
   2410 
   2411         if (tn == pTrack->GetNumber())
   2412             return pTrack;
   2413     }
   2414 
   2415     return NULL;  //not found
   2416 }
   2417 
   2418 
   2419 Track* Tracks::GetTrackByIndex(unsigned long idx) const
   2420 {
   2421     const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
   2422 
   2423     if (idx >= static_cast<unsigned long>(count))
   2424          return NULL;
   2425 
   2426     return m_trackEntries[idx];
   2427 }
   2428 
   2429 
   2430 void Cluster::Load()
   2431 {
   2432     assert(m_pSegment);
   2433 
   2434     if (m_start > 0)
   2435     {
   2436         assert(m_size > 0);
   2437         assert(m_timecode >= 0);
   2438         return;
   2439     }
   2440 
   2441     assert(m_size == 0);
   2442     assert(m_timecode < 0);
   2443 
   2444     IMkvReader* const pReader = m_pSegment->m_pReader;
   2445 
   2446     const long long off = -m_start;  //relative to segment
   2447     long long pos = m_pSegment->m_start + off;  //absolute
   2448 
   2449     long len;
   2450 
   2451     const long long id_ = ReadUInt(pReader, pos, len);
   2452     assert(id_ >= 0);
   2453     assert(id_ == 0x0F43B675);  //Cluster ID
   2454 
   2455     pos += len;  //consume id
   2456 
   2457     const long long size_ = ReadUInt(pReader, pos, len);
   2458     assert(size_ >= 0);
   2459 
   2460     pos += len;  //consume size
   2461 
   2462     m_start = pos;
   2463     m_size = size_;
   2464 
   2465     const long long stop = m_start + size_;
   2466 
   2467     long long timecode = -1;
   2468 
   2469     while (pos < stop)
   2470     {
   2471         if (Match(pReader, pos, 0x67, timecode))
   2472             break;
   2473         else
   2474         {
   2475             const long long id = ReadUInt(pReader, pos, len);
   2476             assert(id >= 0);  //TODO
   2477             assert((pos + len) <= stop);
   2478 
   2479             pos += len;  //consume id
   2480 
   2481             const long long size = ReadUInt(pReader, pos, len);
   2482             assert(size >= 0);  //TODO
   2483             assert((pos + len) <= stop);
   2484 
   2485             pos += len;  //consume size
   2486 
   2487             if (id == 0x20)  //BlockGroup ID
   2488                 break;
   2489 
   2490             if (id == 0x23)  //SimpleBlock ID
   2491                 break;
   2492 
   2493             pos += size;  //consume payload
   2494             assert(pos <= stop);
   2495         }
   2496     }
   2497 
   2498     assert(pos <= stop);
   2499     assert(timecode >= 0);
   2500 
   2501     m_timecode = timecode;
   2502 }
   2503 
   2504 
   2505 Cluster* Cluster::Parse(
   2506     Segment* pSegment,
   2507     size_t idx,
   2508     long long off)
   2509 {
   2510     assert(pSegment);
   2511     assert(off >= 0);
   2512     assert(off < pSegment->m_size);
   2513     Cluster* const pCluster = new Cluster(pSegment, idx, -off);
   2514     assert(pCluster);
   2515 
   2516     return pCluster;
   2517 }
   2518 
   2519 
   2520 Cluster::Cluster() :
   2521     m_pSegment(NULL),
   2522     m_index(0),
   2523     m_start(0),
   2524     m_size(0),
   2525     m_timecode(0),
   2526     m_pEntries(NULL),
   2527     m_entriesCount(0)
   2528 {
   2529 }
   2530 
   2531 Cluster::Cluster(
   2532     Segment* pSegment,
   2533     size_t idx,
   2534     long long off) :
   2535     m_pSegment(pSegment),
   2536     m_index(idx),
   2537     m_start(off),
   2538     m_size(0),
   2539     m_timecode(-1),
   2540     m_pEntries(NULL),
   2541     m_entriesCount(0)
   2542 {
   2543 }
   2544 
   2545 
   2546 Cluster::~Cluster()
   2547 {
   2548 #if 0
   2549     while (!m_pEntries.empty())
   2550     {
   2551         BlockEntry* pBlockEntry = m_pEntries.front();
   2552         assert(pBlockEntry);
   2553 
   2554         m_pEntries.pop_front();
   2555         delete pBlockEntry;
   2556     }
   2557 #else
   2558     BlockEntry** i = m_pEntries;
   2559     BlockEntry** const j = m_pEntries + m_entriesCount;
   2560     while (i != j)
   2561     {
   2562          BlockEntry* p = *i++;
   2563 
   2564          assert(p);
   2565          delete p;
   2566     }
   2567 
   2568     delete[] m_pEntries;
   2569 #endif
   2570 
   2571 }
   2572 
   2573 bool Cluster::EOS() const
   2574 {
   2575     return (m_pSegment == 0);
   2576 }
   2577 
   2578 
   2579 void Cluster::LoadBlockEntries()
   2580 {
   2581     if (m_pEntries)
   2582         return;
   2583 
   2584     Load();
   2585     assert(m_timecode >= 0);
   2586     assert(m_start > 0);
   2587     assert(m_size > 0);
   2588 
   2589     IMkvReader* const pReader = m_pSegment->m_pReader;
   2590 
   2591     long long pos = m_start;
   2592     const long long stop = m_start + m_size;
   2593     long long timecode = -1;
   2594 
   2595     long long idx = pos;
   2596 
   2597     m_entriesCount = 0;
   2598 
   2599     while (idx < stop)
   2600     {
   2601         if (Match(pReader, idx, 0x67, timecode))
   2602             assert(timecode == m_timecode);
   2603         else
   2604         {
   2605             long len;
   2606 
   2607             const long long id = ReadUInt(pReader, idx, len);
   2608             assert(id >= 0);  //TODO
   2609             assert((idx + len) <= stop);
   2610 
   2611             idx += len;  //consume id
   2612 
   2613             const long long size = ReadUInt(pReader, idx, len);
   2614             assert(size >= 0);  //TODO
   2615             assert((idx + len) <= stop);
   2616 
   2617             idx += len;  //consume size
   2618 
   2619             if (id == 0x20)  //BlockGroup ID
   2620                 ++m_entriesCount;
   2621             else if (id == 0x23)  //SimpleBlock ID
   2622                 ++m_entriesCount;
   2623 
   2624             idx += size;  //consume payload
   2625 
   2626             assert(idx <= stop);
   2627         }
   2628     }
   2629 
   2630     if (m_entriesCount == 0)
   2631         return;
   2632 
   2633     m_pEntries = new BlockEntry*[m_entriesCount];
   2634     size_t index = 0;
   2635 
   2636     while (pos < stop)
   2637     {
   2638         if (Match(pReader, pos, 0x67, timecode))
   2639             assert(timecode == m_timecode);
   2640         else
   2641         {
   2642             long len;
   2643             const long long id = ReadUInt(pReader, pos, len);
   2644             assert(id >= 0);  //TODO
   2645             assert((pos + len) <= stop);
   2646 
   2647             pos += len;  //consume id
   2648 
   2649             const long long size = ReadUInt(pReader, pos, len);
   2650             assert(size >= 0);  //TODO
   2651             assert((pos + len) <= stop);
   2652 
   2653             pos += len;  //consume size
   2654 
   2655             if (id == 0x20)  //BlockGroup ID
   2656                 ParseBlockGroup(pos, size, index++);
   2657             else if (id == 0x23)  //SimpleBlock ID
   2658                 ParseSimpleBlock(pos, size, index++);
   2659 
   2660             pos += size;  //consume payload
   2661             assert(pos <= stop);
   2662         }
   2663     }
   2664 
   2665     assert(pos == stop);
   2666     assert(timecode >= 0);
   2667     assert(index == m_entriesCount);
   2668 }
   2669 
   2670 
   2671 
   2672 long long Cluster::GetTimeCode()
   2673 {
   2674     Load();
   2675     return m_timecode;
   2676 }
   2677 
   2678 
   2679 long long Cluster::GetTime()
   2680 {
   2681     const long long tc = GetTimeCode();
   2682     assert(tc >= 0);
   2683 
   2684     const SegmentInfo* const pInfo = m_pSegment->GetInfo();
   2685     assert(pInfo);
   2686 
   2687     const long long scale = pInfo->GetTimeCodeScale();
   2688     assert(scale >= 1);
   2689 
   2690     const long long t = m_timecode * scale;
   2691 
   2692     return t;
   2693 }
   2694 
   2695 
   2696 void Cluster::ParseBlockGroup(long long start, long long size, size_t index)
   2697 {
   2698     assert(m_pEntries);
   2699     assert(m_entriesCount);
   2700     assert(index < m_entriesCount);
   2701 
   2702     BlockGroup* const pGroup = new BlockGroup(this, index, start, size);
   2703     assert(pGroup);  //TODO
   2704 
   2705     m_pEntries[index] = pGroup;
   2706 }
   2707 
   2708 
   2709 
   2710 void Cluster::ParseSimpleBlock(long long start, long long size, size_t index)
   2711 {
   2712     assert(m_pEntries);
   2713     assert(m_entriesCount);
   2714     assert(index < m_entriesCount);
   2715 
   2716     SimpleBlock* const pSimpleBlock = new SimpleBlock(this, index, start, size);
   2717     assert(pSimpleBlock);  //TODO
   2718 
   2719     m_pEntries[index] = pSimpleBlock;
   2720 }
   2721 
   2722 
   2723 const BlockEntry* Cluster::GetFirst()
   2724 {
   2725     LoadBlockEntries();
   2726 
   2727     return m_pEntries[0];
   2728 }
   2729 
   2730 
   2731 const BlockEntry* Cluster::GetLast()
   2732 {
   2733     if (m_entriesCount == 0)
   2734         return m_pEntries[0];
   2735 
   2736     return m_pEntries[m_entriesCount-1];
   2737 }
   2738 
   2739 
   2740 const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
   2741 {
   2742     assert(pEntry);
   2743 
   2744     size_t idx = pEntry->GetIndex();
   2745 
   2746     ++idx;
   2747 
   2748     if (idx == m_entriesCount)
   2749       return NULL;
   2750 
   2751     return m_pEntries[idx];
   2752 
   2753 }
   2754 
   2755 
   2756 const BlockEntry* Cluster::GetEntry(const Track* pTrack)
   2757 {
   2758 
   2759     assert(pTrack);
   2760 
   2761     if (m_pSegment == NULL)  //EOS
   2762         return pTrack->GetEOS();
   2763 
   2764     LoadBlockEntries();
   2765 
   2766     BlockEntry* i = *m_pEntries;
   2767     BlockEntry* j = *m_pEntries + m_entriesCount;
   2768     while (i != j)
   2769     {
   2770         BlockEntry* pEntry = i;
   2771         i++;
   2772         assert(pEntry);
   2773         assert(!pEntry->EOS());
   2774 
   2775         const Block* const pBlock = pEntry->GetBlock();
   2776         assert(pBlock);
   2777 
   2778         if (pBlock->GetTrackNumber() != pTrack->GetNumber())
   2779             continue;
   2780 
   2781         if (pTrack->VetEntry(pEntry))
   2782             return pEntry;
   2783     }
   2784 
   2785     return pTrack->GetEOS();  //no satisfactory block found
   2786 }
   2787 
   2788 
   2789 BlockEntry::BlockEntry()
   2790 {
   2791 }
   2792 
   2793 
   2794 BlockEntry::~BlockEntry()
   2795 {
   2796 }
   2797 
   2798 
   2799 
   2800 SimpleBlock::SimpleBlock(
   2801     Cluster* pCluster,
   2802     size_t idx,
   2803     long long start,
   2804     long long size) :
   2805     m_pCluster(pCluster),
   2806     m_index(idx),
   2807     m_block(start, size, pCluster->m_pSegment->m_pReader)
   2808 {
   2809 }
   2810 
   2811 
   2812 bool SimpleBlock::EOS() const
   2813 {
   2814     return false;
   2815 }
   2816 
   2817 
   2818 Cluster* SimpleBlock::GetCluster() const
   2819 {
   2820     return m_pCluster;
   2821 }
   2822 
   2823 
   2824 size_t SimpleBlock::GetIndex() const
   2825 {
   2826     return m_index;
   2827 }
   2828 
   2829 
   2830 const Block* SimpleBlock::GetBlock() const
   2831 {
   2832     return &m_block;
   2833 }
   2834 
   2835 
   2836 bool SimpleBlock::IsBFrame() const
   2837 {
   2838     return false;
   2839 }
   2840 
   2841 
   2842 BlockGroup::BlockGroup(
   2843     Cluster* pCluster,
   2844     size_t idx,
   2845     long long start,
   2846     long long size_) :
   2847     m_pCluster(pCluster),
   2848     m_index(idx),
   2849     m_prevTimeCode(0),
   2850     m_nextTimeCode(0),
   2851     m_pBlock(NULL)  //TODO: accept multiple blocks within a block group
   2852 {
   2853     IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
   2854 
   2855     long long pos = start;
   2856     const long long stop = start + size_;
   2857 
   2858     bool bSimpleBlock = false;
   2859 
   2860     while (pos < stop)
   2861     {
   2862         short t;
   2863 
   2864         if (Match(pReader, pos, 0x7B, t))
   2865         {
   2866             if (t < 0)
   2867                 m_prevTimeCode = t;
   2868             else if (t > 0)
   2869                 m_nextTimeCode = t;
   2870             else
   2871                 assert(false);
   2872         }
   2873         else
   2874         {
   2875             long len;
   2876             const long long id = ReadUInt(pReader, pos, len);
   2877             assert(id >= 0);  //TODO
   2878             assert((pos + len) <= stop);
   2879 
   2880             pos += len;  //consume ID
   2881 
   2882             const long long size = ReadUInt(pReader, pos, len);
   2883             assert(size >= 0);  //TODO
   2884             assert((pos + len) <= stop);
   2885 
   2886             pos += len;  //consume size
   2887 
   2888             switch (id)
   2889             {
   2890                 case 0x23:  //SimpleBlock ID
   2891                     bSimpleBlock = true;
   2892                     //YES, FALL THROUGH TO NEXT CASE
   2893 
   2894                 case 0x21:  //Block ID
   2895                     ParseBlock(pos, size);
   2896                     break;
   2897 
   2898                 default:
   2899                     break;
   2900             }
   2901 
   2902             pos += size;  //consume payload
   2903             assert(pos <= stop);
   2904         }
   2905     }
   2906 
   2907     assert(pos == stop);
   2908     assert(m_pBlock);
   2909 
   2910     if (!bSimpleBlock)
   2911         m_pBlock->SetKey(m_prevTimeCode >= 0);
   2912 }
   2913 
   2914 
   2915 BlockGroup::~BlockGroup()
   2916 {
   2917     delete m_pBlock;
   2918 }
   2919 
   2920 
   2921 void BlockGroup::ParseBlock(long long start, long long size)
   2922 {
   2923     IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
   2924 
   2925     Block* const pBlock = new Block(start, size, pReader);
   2926     assert(pBlock);  //TODO
   2927 
   2928     //TODO: the Matroska spec says you have multiple blocks within the
   2929     //same block group, with blocks ranked by priority (the flag bits).
   2930     //I haven't ever seen such a file (mkvmux certainly doesn't make
   2931     //one), so until then I'll just assume block groups contain a single
   2932     //block.
   2933 #if 0
   2934     m_blocks.push_back(pBlock);
   2935 #else
   2936     assert(m_pBlock == NULL);
   2937     m_pBlock = pBlock;
   2938 #endif
   2939 
   2940 #if 0
   2941     Track* const pTrack = pBlock->GetTrack();
   2942     assert(pTrack);
   2943 
   2944     pTrack->Insert(pBlock);
   2945 #endif
   2946 }
   2947 
   2948 
   2949 bool BlockGroup::EOS() const
   2950 {
   2951     return false;
   2952 }
   2953 
   2954 
   2955 Cluster* BlockGroup::GetCluster() const
   2956 {
   2957     return m_pCluster;
   2958 }
   2959 
   2960 
   2961 size_t BlockGroup::GetIndex() const
   2962 {
   2963     return m_index;
   2964 }
   2965 
   2966 
   2967 const Block* BlockGroup::GetBlock() const
   2968 {
   2969     return m_pBlock;
   2970 }
   2971 
   2972 
   2973 short BlockGroup::GetPrevTimeCode() const
   2974 {
   2975     return m_prevTimeCode;
   2976 }
   2977 
   2978 
   2979 short BlockGroup::GetNextTimeCode() const
   2980 {
   2981     return m_nextTimeCode;
   2982 }
   2983 
   2984 
   2985 bool BlockGroup::IsBFrame() const
   2986 {
   2987     return (m_nextTimeCode > 0);
   2988 }
   2989 
   2990 
   2991 
   2992 Block::Block(long long start, long long size_, IMkvReader* pReader) :
   2993     m_start(start),
   2994     m_size(size_)
   2995 {
   2996     long long pos = start;
   2997     const long long stop = start + size_;
   2998 
   2999     long len;
   3000 
   3001     m_track = ReadUInt(pReader, pos, len);
   3002     assert(m_track > 0);
   3003     assert((pos + len) <= stop);
   3004 
   3005     pos += len;  //consume track number
   3006     assert((stop - pos) >= 2);
   3007 
   3008     m_timecode = Unserialize2SInt(pReader, pos);
   3009 
   3010     pos += 2;
   3011     assert((stop - pos) >= 1);
   3012 
   3013     const long hr = pReader->Read(pos, 1, &m_flags);
   3014     assert(hr == 0L);
   3015 
   3016     ++pos;
   3017     assert(pos <= stop);
   3018 
   3019     m_frameOff = pos;
   3020 
   3021     const long long frame_size = stop - pos;
   3022 
   3023     assert(frame_size <= 2147483647L);
   3024 
   3025     m_frameSize = static_cast<long>(frame_size);
   3026 }
   3027 
   3028 
   3029 long long Block::GetTimeCode(Cluster* pCluster) const
   3030 {
   3031     assert(pCluster);
   3032 
   3033     const long long tc0 = pCluster->GetTimeCode();
   3034     assert(tc0 >= 0);
   3035 
   3036     const long long tc = tc0 + static_cast<long long>(m_timecode);
   3037     assert(tc >= 0);
   3038 
   3039     return tc;  //unscaled timecode units
   3040 }
   3041 
   3042 
   3043 long long Block::GetTime(Cluster* pCluster) const
   3044 {
   3045     assert(pCluster);
   3046 
   3047     const long long tc = GetTimeCode(pCluster);
   3048 
   3049     const Segment* const pSegment = pCluster->m_pSegment;
   3050     const SegmentInfo* const pInfo = pSegment->GetInfo();
   3051     assert(pInfo);
   3052 
   3053     const long long scale = pInfo->GetTimeCodeScale();
   3054     assert(scale >= 1);
   3055 
   3056     const long long ns = tc * scale;
   3057 
   3058     return ns;
   3059 }
   3060 
   3061 
   3062 unsigned long Block::GetTrackNumber() const
   3063 {
   3064     assert(m_track > 0);
   3065 
   3066     return static_cast<unsigned long>(m_track);
   3067 }
   3068 
   3069 
   3070 bool Block::IsKey() const
   3071 {
   3072     return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
   3073 }
   3074 
   3075 
   3076 void Block::SetKey(bool bKey)
   3077 {
   3078     if (bKey)
   3079         m_flags |= static_cast<unsigned char>(1 << 7);
   3080     else
   3081         m_flags &= 0x7F;
   3082 }
   3083 
   3084 
   3085 long Block::GetSize() const
   3086 {
   3087     return m_frameSize;
   3088 }
   3089 
   3090 
   3091 long Block::Read(IMkvReader* pReader, unsigned char* buf) const
   3092 {
   3093 
   3094     assert(pReader);
   3095     assert(buf);
   3096 
   3097     const long hr = pReader->Read(m_frameOff, m_frameSize, buf);
   3098 
   3099     return hr;
   3100 }
   3101 
   3102 
   3103 }  //end namespace mkvparser
   3104