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
30namespace mkvparser {
31const float MasteringMetadata::kValueNotPresent = FLT_MAX;
32const long long Colour::kValueNotPresent = LLONG_MAX;
33const float Projection::kValueNotPresent = FLT_MAX;
34
35#ifdef MSC_COMPAT
36inline bool isnan(double val) { return !!_isnan(val); }
37inline bool isinf(double val) { return !_finite(val); }
38#else
39inline bool isnan(double val) { return std::isnan(val); }
40inline bool isinf(double val) { return std::isinf(val); }
41#endif  // MSC_COMPAT
42
43IMkvReader::~IMkvReader() {}
44
45template <typename Type>
46Type* 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
61void GetVersion(int& major, int& minor, int& build, int& revision) {
62  major = 1;
63  minor = 0;
64  build = 0;
65  revision = 30;
66}
67
68long 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.
124long 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
178long 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.
215long 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
238long 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
296long 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
328long 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
358long 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
399bool 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
437bool 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
496EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
497
498EBMLHeader::~EBMLHeader() { delete[] m_docType; }
499
500void 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
515long 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
665Segment::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
686Segment::~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
707long 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
824long 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
1030long 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
1039long 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
1315long 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
1341bool 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
1400bool 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
1454long 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
1484SeekHead::Entry::Entry() : id(0), pos(0), element_start(0), element_size(0) {}
1485
1486SeekHead::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
1498SeekHead::~SeekHead() {
1499  delete[] m_entries;
1500  delete[] m_void_elements;
1501}
1502
1503long 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
1604int SeekHead::GetCount() const { return m_entry_count; }
1605
1606const 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
1616int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
1617
1618const 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
1628long 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
1744bool 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
1827Cues::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
1839Cues::~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
1855long Cues::GetCount() const {
1856  if (m_cue_points == NULL)
1857    return -1;
1858
1859  return m_count;  // TODO: really ignore preload count?
1860}
1861
1862bool Cues::DoneParsing() const {
1863  const long long stop = m_start + m_size;
1864  return (m_pos >= stop);
1865}
1866
1867bool 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
1913bool 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
1946bool 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
2010bool 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
2075const 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
2090const 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
2107const 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
2134const 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
2142const 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
2199const 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
2258CuePoint::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
2268CuePoint::~CuePoint() { delete[] m_track_positions; }
2269
2270bool 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
2391bool 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
2437const 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
2457long long CuePoint::GetTimeCode() const { return m_timecode; }
2458
2459long 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
2474bool 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
2494const 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
2504const 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
2516unsigned long Segment::GetCount() const { return m_clusterCount; }
2517
2518const 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
2691long 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
2834long 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
3160const 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
3215const Tracks* Segment::GetTracks() const { return m_pTracks; }
3216const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
3217const Cues* Segment::GetCues() const { return m_pCues; }
3218const Chapters* Segment::GetChapters() const { return m_pChapters; }
3219const Tags* Segment::GetTags() const { return m_pTags; }
3220const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
3221
3222long long Segment::GetDuration() const {
3223  assert(m_pInfo);
3224  return m_pInfo->GetDuration();
3225}
3226
3227Chapters::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
3239Chapters::~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
3247long 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
3281int Chapters::GetEditionCount() const { return m_editions_count; }
3282
3283const 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
3293bool 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
3315long 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
3325Chapters::Edition::Edition() {}
3326
3327Chapters::Edition::~Edition() {}
3328
3329int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
3330
3331const 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
3341void Chapters::Edition::Init() {
3342  m_atoms = NULL;
3343  m_atoms_size = 0;
3344  m_atoms_count = 0;
3345}
3346
3347void 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
3353void 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
3365long 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
3397long 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
3408bool 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
3430Chapters::Atom::Atom() {}
3431
3432Chapters::Atom::~Atom() {}
3433
3434unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
3435
3436const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
3437
3438long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
3439
3440long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
3441
3442long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
3443  return GetTime(pChapters, m_start_timecode);
3444}
3445
3446long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
3447  return GetTime(pChapters, m_stop_timecode);
3448}
3449
3450int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
3451
3452const 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
3462void 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
3473void 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
3484void 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
3499long 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
3557long 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
3585long 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
3596bool 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
3618Chapters::Display::Display() {}
3619
3620Chapters::Display::~Display() {}
3621
3622const char* Chapters::Display::GetString() const { return m_string; }
3623
3624const char* Chapters::Display::GetLanguage() const { return m_language; }
3625
3626const char* Chapters::Display::GetCountry() const { return m_country; }
3627
3628void Chapters::Display::Init() {
3629  m_string = NULL;
3630  m_language = NULL;
3631  m_country = NULL;
3632}
3633
3634void 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
3640void 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
3651long 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
3693Tags::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
3704Tags::~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
3712long 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
3747int Tags::GetTagCount() const { return m_tags_count; }
3748
3749const 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
3759bool 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
3781long 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
3791Tags::Tag::Tag() {}
3792
3793Tags::Tag::~Tag() {}
3794
3795int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
3796
3797const 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
3807void Tags::Tag::Init() {
3808  m_simple_tags = NULL;
3809  m_simple_tags_size = 0;
3810  m_simple_tags_count = 0;
3811}
3812
3813void 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
3819void 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
3831long 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
3862long 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
3873bool 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
3895Tags::SimpleTag::SimpleTag() {}
3896
3897Tags::SimpleTag::~SimpleTag() {}
3898
3899const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
3900
3901const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
3902
3903void Tags::SimpleTag::Init() {
3904  m_tag_name = NULL;
3905  m_tag_string = NULL;
3906}
3907
3908void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
3909  rhs.m_tag_name = m_tag_name;
3910  rhs.m_tag_string = m_tag_string;
3911}
3912
3913void 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
3921long 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
3958SegmentInfo::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
3969SegmentInfo::~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
3980long 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
4049long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
4050
4051long 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
4063const char* SegmentInfo::GetMuxingAppAsUTF8() const {
4064  return m_pMuxingAppAsUTF8;
4065}
4066
4067const char* SegmentInfo::GetWritingAppAsUTF8() const {
4068  return m_pWritingAppAsUTF8;
4069}
4070
4071const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
4072
4073///////////////////////////////////////////////////////////////
4074// ContentEncoding element
4075ContentEncoding::ContentCompression::ContentCompression()
4076    : algo(0), settings(NULL), settings_len(0) {}
4077
4078ContentEncoding::ContentCompression::~ContentCompression() {
4079  delete[] settings;
4080}
4081
4082ContentEncoding::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
4093ContentEncoding::ContentEncryption::~ContentEncryption() {
4094  delete[] key_id;
4095  delete[] signature;
4096  delete[] sig_key_id;
4097}
4098
4099ContentEncoding::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
4108ContentEncoding::~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
4130const ContentEncoding::ContentCompression*
4131ContentEncoding::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
4141unsigned 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
4148const 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
4159unsigned 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
4166long 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
4195long 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
4295long 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
4350long 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
4454Track::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
4461Track::~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
4476long 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
4498Track::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
4511Track::Info::~Info() { Clear(); }
4512
4513void 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
4531int 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
4557int 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
4610const BlockEntry* Track::GetEOS() const { return &m_eos; }
4611
4612long Track::GetType() const { return m_info.type; }
4613
4614long Track::GetNumber() const { return m_info.number; }
4615
4616unsigned long long Track::GetUid() const { return m_info.uid; }
4617
4618const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
4619
4620const char* Track::GetLanguage() const { return m_info.language; }
4621
4622const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
4623
4624const char* Track::GetCodecId() const { return m_info.codecId; }
4625
4626const unsigned char* Track::GetCodecPrivate(size_t& size) const {
4627  size = m_info.codecPrivateSize;
4628  return m_info.codecPrivate;
4629}
4630
4631bool Track::GetLacing() const { return m_info.lacing; }
4632
4633unsigned long long Track::GetDefaultDuration() const {
4634  return m_info.defaultDuration;
4635}
4636
4637unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
4638
4639unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
4640
4641long 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
4708long 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
4794bool 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
4811long 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
4890const 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
4902unsigned 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
4910long 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
4977Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
4978
4979BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
4980
4981const Block* Track::EOSBlock::GetBlock() const { return NULL; }
4982
4983bool 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
5013bool 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
5094bool 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
5192bool 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
5270VideoTrack::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
5276VideoTrack::~VideoTrack() {
5277  delete m_colour;
5278  delete m_projection;
5279}
5280
5281long 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
5402bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
5403  return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
5404}
5405
5406long 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
5495Colour* VideoTrack::GetColour() const { return m_colour; }
5496
5497Projection* VideoTrack::GetProjection() const { return m_projection; }
5498
5499long long VideoTrack::GetWidth() const { return m_width; }
5500
5501long long VideoTrack::GetHeight() const { return m_height; }
5502
5503long long VideoTrack::GetDisplayWidth() const {
5504  return m_display_width > 0 ? m_display_width : GetWidth();
5505}
5506
5507long long VideoTrack::GetDisplayHeight() const {
5508  return m_display_height > 0 ? m_display_height : GetHeight();
5509}
5510
5511long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }
5512
5513long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }
5514
5515double VideoTrack::GetFrameRate() const { return m_rate; }
5516
5517AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
5518                       long long element_size)
5519    : Track(pSegment, element_start, element_size) {}
5520
5521long 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
5602double AudioTrack::GetSamplingRate() const { return m_rate; }
5603
5604long long AudioTrack::GetChannels() const { return m_channels; }
5605
5606long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
5607
5608Tracks::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
5618long 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
5705unsigned 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
5712long 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
5958Tracks::~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
5970const 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
5990const 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
5999long 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
6224long 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
6414long 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
6512long 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
6721long 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
6754Cluster* 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
6766Cluster::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
6778Cluster::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
6791Cluster::~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
6810bool Cluster::EOS() const { return (m_pSegment == NULL); }
6811
6812long Cluster::GetIndex() const { return m_index; }
6813
6814long 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
6821long long Cluster::GetElementSize() const { return m_element_size; }
6822
6823long 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
7034long 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
7046long 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
7063long 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
7080long 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
7097long 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
7146long 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
7253long 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
7284long 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
7310long 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
7341long 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
7379long Cluster::GetEntryCount() const { return m_entries_count; }
7380
7381const 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
7443const 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
7543BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
7544BlockEntry::~BlockEntry() {}
7545const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
7546long BlockEntry::GetIndex() const { return m_index; }
7547
7548SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
7549                         long long size)
7550    : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
7551
7552long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
7553BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
7554const Block* SimpleBlock::GetBlock() const { return &m_block; }
7555
7556BlockGroup::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
7565long 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
7576BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
7577const Block* BlockGroup::GetBlock() const { return &m_block; }
7578long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
7579long long BlockGroup::GetNextTimeCode() const { return m_next; }
7580long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
7581
7582Block::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
7592Block::~Block() { delete[] m_frames; }
7593
7594long 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
7960long 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
7972long 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
7989long long Block::GetTrackNumber() const { return m_track; }
7990
7991bool Block::IsKey() const {
7992  return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
7993}
7994
7995void Block::SetKey(bool bKey) {
7996  if (bKey)
7997    m_flags |= static_cast<unsigned char>(1 << 7);
7998  else
7999    m_flags &= 0x7F;
8000}
8001
8002bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
8003
8004Block::Lacing Block::GetLacing() const {
8005  const int value = int(m_flags & 0x06) >> 1;
8006  return static_cast<Lacing>(value);
8007}
8008
8009int Block::GetFrameCount() const { return m_frame_count; }
8010
8011const 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
8022long 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
8030long long Block::GetDiscardPadding() const { return m_discard_padding; }
8031
8032}  // namespace mkvparser
8033