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