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