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