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