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