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