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