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