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