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