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
isnan(double val)30 inline bool isnan(double val) { return !!_isnan(val); }
isinf(double val)31 inline bool isinf(double val) { return !_finite(val); }
32 #else
isnan(double val)33 inline bool isnan(double val) { return std::isnan(val); }
isinf(double val)34 inline bool isinf(double val) { return std::isinf(val); }
35 #endif  // MSC_COMPAT
36 
~IMkvReader()37 IMkvReader::~IMkvReader() {}
38 
39 template <typename Type>
SafeArrayAlloc(unsigned long long num_elements,unsigned long long element_size)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 
GetVersion(int & major,int & minor,int & build,int & revision)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 
ReadUInt(IMkvReader * pReader,long long pos,long & len)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.
ReadID(IMkvReader * pReader,long long pos,long & len)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 
GetUIntLength(IMkvReader * pReader,long long pos,long & len)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.
UnserializeUInt(IMkvReader * pReader,long long pos,long long size)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 
UnserializeFloat(IMkvReader * pReader,long long pos,long long size_,double & result)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 
UnserializeInt(IMkvReader * pReader,long long pos,long long size,long long & result_ref)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 
UnserializeString(IMkvReader * pReader,long long pos,long long size,char * & str)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 
ParseElementHeader(IMkvReader * pReader,long long & pos,long long stop,long long & id,long long & size)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 
Match(IMkvReader * pReader,long long & pos,unsigned long expected_id,long long & val)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 
Match(IMkvReader * pReader,long long & pos,unsigned long expected_id,unsigned char * & buf,size_t & buflen)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 
EBMLHeader()490 EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
491 
~EBMLHeader()492 EBMLHeader::~EBMLHeader() { delete[] m_docType; }
493 
Init()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 
Parse(IMkvReader * pReader,long long & pos)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 
Segment(IMkvReader * pReader,long long elem_start,long long start,long long size)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 
~Segment()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 
CreateInstance(IMkvReader * pReader,long long pos,Segment * & pSegment)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 
ParseHeaders()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 
LoadCluster(long long & pos,long & len)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 
DoLoadCluster(long long & pos,long & len)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 
DoLoadClusterUnknownSize(long long & pos,long & len)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 
AppendCluster(Cluster * pCluster)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 
PreloadCluster(Cluster * pCluster,ptrdiff_t idx)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 
Load()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 
SeekHead(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)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 
~SeekHead()1490 SeekHead::~SeekHead() {
1491   delete[] m_entries;
1492   delete[] m_void_elements;
1493 }
1494 
Parse()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 
GetCount() const1592 int SeekHead::GetCount() const { return m_entry_count; }
1593 
GetEntry(int idx) const1594 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 
GetVoidElementCount() const1604 int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
1605 
GetVoidElement(int idx) const1606 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 
ParseCues(long long off,long long & pos,long & len)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 
ParseEntry(IMkvReader * pReader,long long start,long long size_,Entry * pEntry)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 
Cues(Segment * pSegment,long long start_,long long size_,long long element_start,long long element_size)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 
~Cues()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 
GetCount() const1854 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 
DoneParsing() const1861 bool Cues::DoneParsing() const {
1862   const long long stop = m_start + m_size;
1863   return (m_pos >= stop);
1864 }
1865 
Init() const1866 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 
PreloadCuePoint(long & cue_points_size,long long pos) const1912 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 
LoadCuePoint() const1945 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 
Find(long long time_ns,const Track * pTrack,const CuePoint * & pCP,const CuePoint::TrackPosition * & pTP) const2009 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 
GetFirst() const2074 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 
GetLast() const2089 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 
GetNext(const CuePoint * pCurr) const2106 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 
GetBlock(const CuePoint * pCP,const CuePoint::TrackPosition * pTP) const2133 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 
GetBlock(const CuePoint & cp,const CuePoint::TrackPosition & tp)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 
FindOrPreloadCluster(long long requested_pos)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 
CuePoint(long idx,long long pos)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 
~CuePoint()2267 CuePoint::~CuePoint() { delete[] m_track_positions; }
2268 
Load(IMkvReader * pReader)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 
Parse(IMkvReader * pReader,long long start_,long long size_)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 
Find(const Track * pTrack) const2436 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 
GetTimeCode() const2454 long long CuePoint::GetTimeCode() const { return m_timecode; }
2455 
GetTime(const Segment * pSegment) const2456 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 
DoneParsing() const2471 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 
GetFirst() const2491 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 
GetLast() const2501 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 
GetCount() const2513 unsigned long Segment::GetCount() const { return m_clusterCount; }
2514 
GetNext(const Cluster * pCurr)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 
ParseNext(const Cluster * pCurr,const Cluster * & pResult,long long & pos,long & len)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 
DoParseNext(const Cluster * & pResult,long long & pos,long & len)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 
FindCluster(long long time_ns) const3157 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 
GetTracks() const3212 const Tracks* Segment::GetTracks() const { return m_pTracks; }
GetInfo() const3213 const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
GetCues() const3214 const Cues* Segment::GetCues() const { return m_pCues; }
GetChapters() const3215 const Chapters* Segment::GetChapters() const { return m_pChapters; }
GetTags() const3216 const Tags* Segment::GetTags() const { return m_pTags; }
GetSeekHead() const3217 const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
3218 
GetDuration() const3219 long long Segment::GetDuration() const {
3220   assert(m_pInfo);
3221   return m_pInfo->GetDuration();
3222 }
3223 
Chapters(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)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 
~Chapters()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 
Parse()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 
GetEditionCount() const3278 int Chapters::GetEditionCount() const { return m_editions_count; }
3279 
GetEdition(int idx) const3280 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 
ExpandEditionsArray()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 
ParseEdition(long long pos,long long size)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 
Edition()3322 Chapters::Edition::Edition() {}
3323 
~Edition()3324 Chapters::Edition::~Edition() {}
3325 
GetAtomCount() const3326 int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
3327 
GetAtom(int index) const3328 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 
Init()3338 void Chapters::Edition::Init() {
3339   m_atoms = NULL;
3340   m_atoms_size = 0;
3341   m_atoms_count = 0;
3342 }
3343 
ShallowCopy(Edition & rhs) const3344 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 
Clear()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 
Parse(IMkvReader * pReader,long long pos,long long size)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 
ParseAtom(IMkvReader * pReader,long long pos,long long size)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 
ExpandAtomsArray()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 
Atom()3427 Chapters::Atom::Atom() {}
3428 
~Atom()3429 Chapters::Atom::~Atom() {}
3430 
GetUID() const3431 unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
3432 
GetStringUID() const3433 const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
3434 
GetStartTimecode() const3435 long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
3436 
GetStopTimecode() const3437 long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
3438 
GetStartTime(const Chapters * pChapters) const3439 long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
3440   return GetTime(pChapters, m_start_timecode);
3441 }
3442 
GetStopTime(const Chapters * pChapters) const3443 long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
3444   return GetTime(pChapters, m_stop_timecode);
3445 }
3446 
GetDisplayCount() const3447 int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
3448 
GetDisplay(int index) const3449 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 
Init()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 
ShallowCopy(Atom & rhs) const3470 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 
Clear()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 
Parse(IMkvReader * pReader,long long pos,long long size)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 
GetTime(const Chapters * pChapters,long long timecode)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 
ParseDisplay(IMkvReader * pReader,long long pos,long long size)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 
ExpandDisplaysArray()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 
Display()3615 Chapters::Display::Display() {}
3616 
~Display()3617 Chapters::Display::~Display() {}
3618 
GetString() const3619 const char* Chapters::Display::GetString() const { return m_string; }
3620 
GetLanguage() const3621 const char* Chapters::Display::GetLanguage() const { return m_language; }
3622 
GetCountry() const3623 const char* Chapters::Display::GetCountry() const { return m_country; }
3624 
Init()3625 void Chapters::Display::Init() {
3626   m_string = NULL;
3627   m_language = NULL;
3628   m_country = NULL;
3629 }
3630 
ShallowCopy(Display & rhs) const3631 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 
Clear()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 
Parse(IMkvReader * pReader,long long pos,long long size)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 
Tags(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)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 
~Tags()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 
Parse()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 
GetTagCount() const3744 int Tags::GetTagCount() const { return m_tags_count; }
3745 
GetTag(int idx) const3746 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 
ExpandTagsArray()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 
ParseTag(long long pos,long long size)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 
Tag()3788 Tags::Tag::Tag() {}
3789 
~Tag()3790 Tags::Tag::~Tag() {}
3791 
GetSimpleTagCount() const3792 int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
3793 
GetSimpleTag(int index) const3794 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 
Init()3804 void Tags::Tag::Init() {
3805   m_simple_tags = NULL;
3806   m_simple_tags_size = 0;
3807   m_simple_tags_count = 0;
3808 }
3809 
ShallowCopy(Tag & rhs) const3810 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 
Clear()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 
Parse(IMkvReader * pReader,long long pos,long long size)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 
ParseSimpleTag(IMkvReader * pReader,long long pos,long long size)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 
ExpandSimpleTagsArray()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 
SimpleTag()3892 Tags::SimpleTag::SimpleTag() {}
3893 
~SimpleTag()3894 Tags::SimpleTag::~SimpleTag() {}
3895 
GetTagName() const3896 const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
3897 
GetTagString() const3898 const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
3899 
Init()3900 void Tags::SimpleTag::Init() {
3901   m_tag_name = NULL;
3902   m_tag_string = NULL;
3903 }
3904 
ShallowCopy(SimpleTag & rhs) const3905 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 
Clear()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 
Parse(IMkvReader * pReader,long long pos,long long size)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 
SegmentInfo(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)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 
~SegmentInfo()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 
Parse()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 
GetTimeCodeScale() const4046 long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
4047 
GetDuration() const4048 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 
GetMuxingAppAsUTF8() const4060 const char* SegmentInfo::GetMuxingAppAsUTF8() const {
4061   return m_pMuxingAppAsUTF8;
4062 }
4063 
GetWritingAppAsUTF8() const4064 const char* SegmentInfo::GetWritingAppAsUTF8() const {
4065   return m_pWritingAppAsUTF8;
4066 }
4067 
GetTitleAsUTF8() const4068 const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
4069 
4070 ///////////////////////////////////////////////////////////////
4071 // ContentEncoding element
ContentCompression()4072 ContentEncoding::ContentCompression::ContentCompression()
4073     : algo(0), settings(NULL), settings_len(0) {}
4074 
~ContentCompression()4075 ContentEncoding::ContentCompression::~ContentCompression() {
4076   delete[] settings;
4077 }
4078 
ContentEncryption()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 
~ContentEncryption()4090 ContentEncoding::ContentEncryption::~ContentEncryption() {
4091   delete[] key_id;
4092   delete[] signature;
4093   delete[] sig_key_id;
4094 }
4095 
ContentEncoding()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 
~ContentEncoding()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*
GetCompressionByIndex(unsigned long idx) const4128     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 
GetCompressionCount() const4138 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 
GetEncryptionByIndex(unsigned long idx) const4145 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 
GetEncryptionCount() const4156 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 
ParseContentEncAESSettingsEntry(long long start,long long size,IMkvReader * pReader,ContentEncAESSettings * aes)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 
ParseContentEncodingEntry(long long start,long long size,IMkvReader * pReader)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 
ParseCompressionEntry(long long start,long long size,IMkvReader * pReader,ContentCompression * compression)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 
ParseEncryptionEntry(long long start,long long size,IMkvReader * pReader,ContentEncryption * encryption)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 
Track(Segment * pSegment,long long element_start,long long element_size)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 
~Track()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 
Create(Segment * pSegment,const Info & info,long long element_start,long long element_size,Track * & pResult)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 
Info()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 
~Info()4508 Track::Info::~Info() { Clear(); }
4509 
Clear()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 
CopyStr(char * Info::* str,Info & dst_) const4528 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 
Copy(Info & dst) const4554 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 
GetEOS() const4607 const BlockEntry* Track::GetEOS() const { return &m_eos; }
4608 
GetType() const4609 long Track::GetType() const { return m_info.type; }
4610 
GetNumber() const4611 long Track::GetNumber() const { return m_info.number; }
4612 
GetUid() const4613 unsigned long long Track::GetUid() const { return m_info.uid; }
4614 
GetNameAsUTF8() const4615 const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
4616 
GetLanguage() const4617 const char* Track::GetLanguage() const { return m_info.language; }
4618 
GetCodecNameAsUTF8() const4619 const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
4620 
GetCodecId() const4621 const char* Track::GetCodecId() const { return m_info.codecId; }
4622 
GetCodecPrivate(size_t & size) const4623 const unsigned char* Track::GetCodecPrivate(size_t& size) const {
4624   size = m_info.codecPrivateSize;
4625   return m_info.codecPrivate;
4626 }
4627 
GetLacing() const4628 bool Track::GetLacing() const { return m_info.lacing; }
4629 
GetDefaultDuration() const4630 unsigned long long Track::GetDefaultDuration() const {
4631   return m_info.defaultDuration;
4632 }
4633 
GetCodecDelay() const4634 unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
4635 
GetSeekPreRoll() const4636 unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
4637 
GetFirst(const BlockEntry * & pBlockEntry) const4638 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 
GetNext(const BlockEntry * pCurrEntry,const BlockEntry * & pNextEntry) const4705 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 
VetEntry(const BlockEntry * pBlockEntry) const4791 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 
Seek(long long time_ns,const BlockEntry * & pResult) const4808 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 
GetContentEncodingByIndex(unsigned long idx) const4887 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 
GetContentEncodingCount() const4899 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 
ParseContentEncodingsEntry(long long start,long long size)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 
EOSBlock()4974 Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
4975 
GetKind() const4976 BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
4977 
GetBlock() const4978 const Block* Track::EOSBlock::GetBlock() const { return NULL; }
4979 
Parse(IMkvReader * reader,long long read_pos,long long value_size,bool is_x,PrimaryChromaticity ** chromaticity)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 
Parse(IMkvReader * reader,long long mm_start,long long mm_size,MasteringMetadata ** mm)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 
Parse(IMkvReader * reader,long long colour_start,long long colour_size,Colour ** colour)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 
VideoTrack(Segment * pSegment,long long element_start,long long element_size)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 
~VideoTrack()5195 VideoTrack::~VideoTrack() { delete m_colour; }
5196 
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,VideoTrack * & pResult)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 
VetEntry(const BlockEntry * pBlockEntry) const5313 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
5314   return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
5315 }
5316 
Seek(long long time_ns,const BlockEntry * & pResult) const5317 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 
GetColour() const5406 Colour* VideoTrack::GetColour() const { return m_colour; }
5407 
GetWidth() const5408 long long VideoTrack::GetWidth() const { return m_width; }
5409 
GetHeight() const5410 long long VideoTrack::GetHeight() const { return m_height; }
5411 
GetDisplayWidth() const5412 long long VideoTrack::GetDisplayWidth() const {
5413   return m_display_width > 0 ? m_display_width : GetWidth();
5414 }
5415 
GetDisplayHeight() const5416 long long VideoTrack::GetDisplayHeight() const {
5417   return m_display_height > 0 ? m_display_height : GetHeight();
5418 }
5419 
GetDisplayUnit() const5420 long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }
5421 
GetStereoMode() const5422 long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }
5423 
GetFrameRate() const5424 double VideoTrack::GetFrameRate() const { return m_rate; }
5425 
AudioTrack(Segment * pSegment,long long element_start,long long element_size)5426 AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
5427                        long long element_size)
5428     : Track(pSegment, element_start, element_size) {}
5429 
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,AudioTrack * & pResult)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 
GetSamplingRate() const5511 double AudioTrack::GetSamplingRate() const { return m_rate; }
5512 
GetChannels() const5513 long long AudioTrack::GetChannels() const { return m_channels; }
5514 
GetBitDepth() const5515 long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
5516 
Tracks(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)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 
Parse()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 
GetTracksCount() const5614 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 
ParseTrackEntry(long long track_start,long long track_size,long long element_start,long long element_size,Track * & pResult) const5621 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 
~Tracks()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 
GetTrackByNumber(long tn) const5879 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 
GetTrackByIndex(unsigned long idx) const5899 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 
Load(long long & pos,long & len) const5908 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 
Parse(long long & pos,long & len) const6133 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 
ParseSimpleBlock(long long block_size,long long & pos,long & len)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 
ParseBlockGroup(long long payload_size,long long & pos,long & len)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 
GetEntry(long index,const mkvparser::BlockEntry * & pEntry) const6630 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 
Create(Segment * pSegment,long idx,long long off)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 
Cluster()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 
Cluster(Segment * pSegment,long idx,long long element_start)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 
~Cluster()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 
EOS() const6717 bool Cluster::EOS() const { return (m_pSegment == NULL); }
6718 
GetIndex() const6719 long Cluster::GetIndex() const { return m_index; }
6720 
GetPosition() const6721 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 
GetElementSize() const6728 long long Cluster::GetElementSize() const { return m_element_size; }
6729 
HasBlockEntries(const Segment * pSegment,long long off,long long & pos,long & len)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 
GetTimeCode() const6941 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 
GetTime() const6953 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 
GetFirstTime() const6970 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 
GetLastTime() const6987 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 
CreateBlock(long long id,long long pos,long long size,long long discard_padding)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 
CreateBlockGroup(long long start_offset,long long size,long long discard_padding)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 
CreateSimpleBlock(long long st,long long sz)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 
GetFirst(const BlockEntry * & pFirst) const7191 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 
GetLast(const BlockEntry * & pLast) const7217 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 
GetNext(const BlockEntry * pCurr,const BlockEntry * & pNext) const7248 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 
GetEntryCount() const7286 long Cluster::GetEntryCount() const { return m_entries_count; }
7287 
GetEntry(const Track * pTrack,long long time_ns) const7288 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 
GetEntry(const CuePoint & cp,const CuePoint::TrackPosition & tp) const7350 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 
BlockEntry(Cluster * p,long idx)7450 BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
~BlockEntry()7451 BlockEntry::~BlockEntry() {}
GetCluster() const7452 const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
GetIndex() const7453 long BlockEntry::GetIndex() const { return m_index; }
7454 
SimpleBlock(Cluster * pCluster,long idx,long long start,long long size)7455 SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
7456                          long long size)
7457     : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
7458 
Parse()7459 long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
GetKind() const7460 BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
GetBlock() const7461 const Block* SimpleBlock::GetBlock() const { return &m_block; }
7462 
BlockGroup(Cluster * pCluster,long idx,long long block_start,long long block_size,long long prev,long long next,long long duration,long long discard_padding)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 
Parse()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 
GetKind() const7483 BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
GetBlock() const7484 const Block* BlockGroup::GetBlock() const { return &m_block; }
GetPrevTimeCode() const7485 long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
GetNextTimeCode() const7486 long long BlockGroup::GetNextTimeCode() const { return m_next; }
GetDurationTimeCode() const7487 long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
7488 
Block(long long start,long long size_,long long discard_padding)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 
~Block()7499 Block::~Block() { delete[] m_frames; }
7500 
Parse(const Cluster * pCluster)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 
GetTimeCode(const Cluster * pCluster) const7868 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 
GetTime(const Cluster * pCluster) const7880 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 
GetTrackNumber() const7897 long long Block::GetTrackNumber() const { return m_track; }
7898 
IsKey() const7899 bool Block::IsKey() const {
7900   return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
7901 }
7902 
SetKey(bool bKey)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 
IsInvisible() const7910 bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
7911 
GetLacing() const7912 Block::Lacing Block::GetLacing() const {
7913   const int value = int(m_flags & 0x06) >> 1;
7914   return static_cast<Lacing>(value);
7915 }
7916 
GetFrameCount() const7917 int Block::GetFrameCount() const { return m_frame_count; }
7918 
GetFrame(int idx) const7919 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 
Read(IMkvReader * pReader,unsigned char * buf) const7930 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 
GetDiscardPadding() const7938 long long Block::GetDiscardPadding() const { return m_discard_padding; }
7939 
7940 }  // namespace mkvparser
7941