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