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