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