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