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