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