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