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