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