| Index: source/libvpx/third_party/libwebm/mkvparser.cpp
|
| diff --git a/source/libvpx/third_party/libwebm/mkvparser.cpp b/source/libvpx/third_party/libwebm/mkvparser.cpp
|
| index fc01be526409dafd5c1b6e4c173f052d5fbf2dab..4306a51176ab4705a0fc4e7ae2a430be4dffd5b5 100644
|
| --- a/source/libvpx/third_party/libwebm/mkvparser.cpp
|
| +++ b/source/libvpx/third_party/libwebm/mkvparser.cpp
|
| @@ -7,45 +7,51 @@
|
| // be found in the AUTHORS file in the root of the source tree.
|
|
|
| #include "mkvparser.hpp"
|
| +
|
| #include <cassert>
|
| +#include <climits>
|
| +#include <cmath>
|
| #include <cstring>
|
| #include <new>
|
| -#include <climits>
|
| +
|
| +#include "webmids.hpp"
|
|
|
| #ifdef _MSC_VER
|
| // Disable MSVC warnings that suggest making code non-portable.
|
| #pragma warning(disable : 4996)
|
| #endif
|
|
|
| -mkvparser::IMkvReader::~IMkvReader() {}
|
| +namespace mkvparser {
|
| +
|
| +IMkvReader::~IMkvReader() {}
|
| +
|
| +template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
|
| + unsigned long long element_size) {
|
| + if (num_elements == 0 || element_size == 0)
|
| + return NULL;
|
| +
|
| + const size_t kMaxAllocSize = 0x80000000; // 2GiB
|
| + const unsigned long long num_bytes = num_elements * element_size;
|
| + if (element_size > (kMaxAllocSize / num_elements))
|
| + return NULL;
|
| +
|
| + return new (std::nothrow) Type[num_bytes];
|
| +}
|
|
|
| -void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) {
|
| +void GetVersion(int& major, int& minor, int& build, int& revision) {
|
| major = 1;
|
| minor = 0;
|
| build = 0;
|
| revision = 30;
|
| }
|
|
|
| -long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) {
|
| - assert(pReader);
|
| - assert(pos >= 0);
|
| -
|
| - int status;
|
| -
|
| - //#ifdef _DEBUG
|
| - // long long total, available;
|
| - // status = pReader->Length(&total, &available);
|
| - // assert(status >= 0);
|
| - // assert((total < 0) || (available <= total));
|
| - // assert(pos < available);
|
| - // assert((available - pos) >= 1); //assume here max u-int len is 8
|
| - //#endif
|
| +long long ReadUInt(IMkvReader* pReader, long long pos, long& len) {
|
| + if (!pReader || pos < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| len = 1;
|
| -
|
| unsigned char b;
|
| -
|
| - status = pReader->Read(pos, 1, &b);
|
| + int status = pReader->Read(pos, 1, &b);
|
|
|
| if (status < 0) // error or underflow
|
| return status;
|
| @@ -63,10 +69,6 @@ long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) {
|
| ++len;
|
| }
|
|
|
| - //#ifdef _DEBUG
|
| - // assert((available - pos) >= len);
|
| - //#endif
|
| -
|
| long long result = b & (~m);
|
| ++pos;
|
|
|
| @@ -92,16 +94,76 @@ long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) {
|
| return result;
|
| }
|
|
|
| -long long mkvparser::GetUIntLength(IMkvReader* pReader, long long pos,
|
| - long& len) {
|
| - assert(pReader);
|
| - assert(pos >= 0);
|
| +// Reads an EBML ID and returns it.
|
| +// An ID must at least 1 byte long, cannot exceed 4, and its value must be
|
| +// greater than 0.
|
| +// See known EBML values and EBMLMaxIDLength:
|
| +// http://www.matroska.org/technical/specs/index.html
|
| +// Returns the ID, or a value less than 0 to report an error while reading the
|
| +// ID.
|
| +long long ReadID(IMkvReader* pReader, long long pos, long& len) {
|
| + if (pReader == NULL || pos < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| + // Read the first byte. The length in bytes of the ID is determined by
|
| + // finding the first set bit in the first byte of the ID.
|
| + unsigned char temp_byte = 0;
|
| + int read_status = pReader->Read(pos, 1, &temp_byte);
|
| +
|
| + if (read_status < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
| + else if (read_status > 0) // No data to read.
|
| + return E_BUFFER_NOT_FULL;
|
| +
|
| + if (temp_byte == 0) // ID length > 8 bytes; invalid file.
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| + int bit_pos = 0;
|
| + const int kMaxIdLengthInBytes = 4;
|
| + const int kCheckByte = 0x80;
|
| +
|
| + // Find the first bit that's set.
|
| + bool found_bit = false;
|
| + for (; bit_pos < kMaxIdLengthInBytes; ++bit_pos) {
|
| + if ((kCheckByte >> bit_pos) & temp_byte) {
|
| + found_bit = true;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (!found_bit) {
|
| + // The value is too large to be a valid ID.
|
| + return E_FILE_FORMAT_INVALID;
|
| + }
|
| +
|
| + // Read the remaining bytes of the ID (if any).
|
| + const int id_length = bit_pos + 1;
|
| + long long ebml_id = temp_byte;
|
| + for (int i = 1; i < id_length; ++i) {
|
| + ebml_id <<= 8;
|
| + read_status = pReader->Read(pos + i, 1, &temp_byte);
|
| +
|
| + if (read_status < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
| + else if (read_status > 0)
|
| + return E_BUFFER_NOT_FULL;
|
| +
|
| + ebml_id |= temp_byte;
|
| + }
|
| +
|
| + len = id_length;
|
| + return ebml_id;
|
| +}
|
| +
|
| +long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) {
|
| + if (!pReader || pos < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| long long total, available;
|
|
|
| int status = pReader->Length(&total, &available);
|
| - assert(status >= 0);
|
| - assert((total < 0) || (available <= total));
|
| + if (status < 0 || (total >= 0 && available > total))
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| len = 1;
|
|
|
| @@ -112,11 +174,9 @@ long long mkvparser::GetUIntLength(IMkvReader* pReader, long long pos,
|
|
|
| status = pReader->Read(pos, 1, &b);
|
|
|
| - if (status < 0)
|
| + if (status != 0)
|
| return status;
|
|
|
| - assert(status == 0);
|
| -
|
| if (b == 0) // we can't handle u-int values larger than 8 bytes
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| @@ -132,12 +192,8 @@ long long mkvparser::GetUIntLength(IMkvReader* pReader, long long pos,
|
|
|
| // TODO(vigneshv): This function assumes that unsigned values never have their
|
| // high bit set.
|
| -long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos,
|
| - long long size) {
|
| - assert(pReader);
|
| - assert(pos >= 0);
|
| -
|
| - if ((size <= 0) || (size > 8))
|
| +long long UnserializeUInt(IMkvReader* pReader, long long pos, long long size) {
|
| + if (!pReader || pos < 0 || (size <= 0) || (size > 8))
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| long long result = 0;
|
| @@ -159,12 +215,9 @@ long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos,
|
| return result;
|
| }
|
|
|
| -long mkvparser::UnserializeFloat(IMkvReader* pReader, long long pos,
|
| - long long size_, double& result) {
|
| - assert(pReader);
|
| - assert(pos >= 0);
|
| -
|
| - if ((size_ != 4) && (size_ != 8))
|
| +long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
|
| + double& result) {
|
| + if (!pReader || pos < 0 || ((size_ != 4) && (size_ != 8)))
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| const long size = static_cast<long>(size_);
|
| @@ -195,8 +248,6 @@ long mkvparser::UnserializeFloat(IMkvReader* pReader, long long pos,
|
|
|
| result = f;
|
| } else {
|
| - assert(size == 8);
|
| -
|
| union {
|
| double d;
|
| unsigned long long dd;
|
| @@ -216,28 +267,25 @@ long mkvparser::UnserializeFloat(IMkvReader* pReader, long long pos,
|
| result = d;
|
| }
|
|
|
| + if (std::isinf(result) || std::isnan(result))
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| return 0;
|
| }
|
|
|
| -long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos,
|
| - long long size, long long& result) {
|
| - assert(pReader);
|
| - assert(pos >= 0);
|
| - assert(size > 0);
|
| - assert(size <= 8);
|
| -
|
| - {
|
| - signed char b;
|
| +long UnserializeInt(IMkvReader* pReader, long long pos, long long size,
|
| + long long& result_ref) {
|
| + if (!pReader || pos < 0 || size < 1 || size > 8)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| - const long status = pReader->Read(pos, 1, (unsigned char*)&b);
|
| + signed char first_byte = 0;
|
| + const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte);
|
|
|
| - if (status < 0)
|
| - return status;
|
| -
|
| - result = b;
|
| + if (status < 0)
|
| + return status;
|
|
|
| - ++pos;
|
| - }
|
| + unsigned long long result = first_byte;
|
| + ++pos;
|
|
|
| for (long i = 1; i < size; ++i) {
|
| unsigned char b;
|
| @@ -253,23 +301,24 @@ long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos,
|
| ++pos;
|
| }
|
|
|
| - return 0; // success
|
| + result_ref = static_cast<long long>(result);
|
| + return 0;
|
| }
|
|
|
| -long mkvparser::UnserializeString(IMkvReader* pReader, long long pos,
|
| - long long size_, char*& str) {
|
| +long UnserializeString(IMkvReader* pReader, long long pos, long long size,
|
| + char*& str) {
|
| delete[] str;
|
| str = NULL;
|
|
|
| - if (size_ >= LONG_MAX) // we need (size+1) chars
|
| + if (size >= LONG_MAX || size < 0)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| - const long size = static_cast<long>(size_);
|
| -
|
| - str = new (std::nothrow) char[size + 1];
|
| + // +1 for '\0' terminator
|
| + const long required_size = static_cast<long>(size) + 1;
|
|
|
| + str = SafeArrayAlloc<char>(1, required_size);
|
| if (str == NULL)
|
| - return -1;
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
|
|
|
| @@ -282,137 +331,149 @@ long mkvparser::UnserializeString(IMkvReader* pReader, long long pos,
|
| return status;
|
| }
|
|
|
| - str[size] = '\0';
|
| -
|
| - return 0; // success
|
| + str[required_size - 1] = '\0';
|
| + return 0;
|
| }
|
|
|
| -long mkvparser::ParseElementHeader(IMkvReader* pReader, long long& pos,
|
| - long long stop, long long& id,
|
| - long long& size) {
|
| - if ((stop >= 0) && (pos >= stop))
|
| +long ParseElementHeader(IMkvReader* pReader, long long& pos,
|
| + long long stop, long long& id,
|
| + long long& size) {
|
| + if (stop >= 0 && pos >= stop)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| long len;
|
|
|
| - id = ReadUInt(pReader, pos, len);
|
| + id = ReadID(pReader, pos, len);
|
|
|
| if (id < 0)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| pos += len; // consume id
|
|
|
| - if ((stop >= 0) && (pos >= stop))
|
| + if (stop >= 0 && pos >= stop)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| size = ReadUInt(pReader, pos, len);
|
|
|
| - if (size < 0)
|
| + if (size < 0 || len < 1 || len > 8) {
|
| + // Invalid: Negative payload size, negative or 0 length integer, or integer
|
| + // larger than 64 bits (libwebm cannot handle them).
|
| + return E_FILE_FORMAT_INVALID;
|
| + }
|
| +
|
| + // Avoid rolling over pos when very close to LONG_LONG_MAX.
|
| + const unsigned long long rollover_check =
|
| + static_cast<unsigned long long>(pos) + len;
|
| + if (rollover_check > LONG_LONG_MAX)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| pos += len; // consume length of size
|
|
|
| // pos now designates payload
|
|
|
| - if ((stop >= 0) && ((pos + size) > stop))
|
| + if (stop >= 0 && pos >= stop)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| return 0; // success
|
| }
|
|
|
| -bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_,
|
| - long long& val) {
|
| - assert(pReader);
|
| - assert(pos >= 0);
|
| +bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
|
| + long long& val) {
|
| + if (!pReader || pos < 0)
|
| + return false;
|
|
|
| - long long total, available;
|
| + long long total = 0;
|
| + long long available = 0;
|
|
|
| const long status = pReader->Length(&total, &available);
|
| - assert(status >= 0);
|
| - assert((total < 0) || (available <= total));
|
| - if (status < 0)
|
| + if (status < 0 || (total >= 0 && available > total))
|
| return false;
|
|
|
| - long len;
|
| + long len = 0;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| - assert(id >= 0);
|
| - assert(len > 0);
|
| - assert(len <= 8);
|
| - assert((pos + len) <= available);
|
| + const long long id = ReadID(pReader, pos, len);
|
| + if (id < 0 || (available - pos) > len)
|
| + return false;
|
|
|
| - if ((unsigned long)id != id_)
|
| + if (static_cast<unsigned long>(id) != expected_id)
|
| return false;
|
|
|
| pos += len; // consume id
|
|
|
| const long long size = ReadUInt(pReader, pos, len);
|
| - assert(size >= 0);
|
| - assert(size <= 8);
|
| - assert(len > 0);
|
| - assert(len <= 8);
|
| - assert((pos + len) <= available);
|
| + if (size < 0 || size > 8 || len < 1 || len > 8 || (available - pos) > len)
|
| + return false;
|
|
|
| pos += len; // consume length of size of payload
|
|
|
| val = UnserializeUInt(pReader, pos, size);
|
| - assert(val >= 0);
|
| + if (val < 0)
|
| + return false;
|
|
|
| pos += size; // consume size of payload
|
|
|
| return true;
|
| }
|
|
|
| -bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_,
|
| - unsigned char*& buf, size_t& buflen) {
|
| - assert(pReader);
|
| - assert(pos >= 0);
|
| +bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
|
| + unsigned char*& buf, size_t& buflen) {
|
| + if (!pReader || pos < 0)
|
| + return false;
|
|
|
| - long long total, available;
|
| + long long total = 0;
|
| + long long available = 0;
|
|
|
| long status = pReader->Length(&total, &available);
|
| - assert(status >= 0);
|
| - assert((total < 0) || (available <= total));
|
| - if (status < 0)
|
| + if (status < 0 || (total >= 0 && available > total))
|
| return false;
|
|
|
| - long len;
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| - assert(id >= 0);
|
| - assert(len > 0);
|
| - assert(len <= 8);
|
| - assert((pos + len) <= available);
|
| + long len = 0;
|
| + const long long id = ReadID(pReader, pos, len);
|
| + if (id < 0 || (available - pos) > len)
|
| + return false;
|
|
|
| - if ((unsigned long)id != id_)
|
| + if (static_cast<unsigned long>(id) != expected_id)
|
| return false;
|
|
|
| pos += len; // consume id
|
|
|
| - const long long size_ = ReadUInt(pReader, pos, len);
|
| - assert(size_ >= 0);
|
| - assert(len > 0);
|
| - assert(len <= 8);
|
| - assert((pos + len) <= available);
|
| + const long long size = ReadUInt(pReader, pos, len);
|
| + if (size < 0 || len <= 0 || len > 8 || (available - pos) > len)
|
| + return false;
|
| +
|
| + unsigned long long rollover_check =
|
| + static_cast<unsigned long long>(pos) + len;
|
| + if (rollover_check > LONG_LONG_MAX)
|
| + return false;
|
|
|
| pos += len; // consume length of size of payload
|
| - assert((pos + size_) <= available);
|
|
|
| - const long buflen_ = static_cast<long>(size_);
|
| + rollover_check = static_cast<unsigned long long>(pos) + size;
|
| + if (rollover_check > LONG_LONG_MAX)
|
| + return false;
|
|
|
| - buf = new (std::nothrow) unsigned char[buflen_];
|
| - assert(buf); // TODO
|
| + if ((pos + size) > available)
|
| + return false;
|
| +
|
| + if (size >= LONG_MAX)
|
| + return false;
|
| +
|
| + const long buflen_ = static_cast<long>(size);
|
| +
|
| + buf = SafeArrayAlloc<unsigned char>(1, buflen_);
|
| + if (!buf)
|
| + return false;
|
|
|
| status = pReader->Read(pos, buflen_, buf);
|
| - assert(status == 0); // TODO
|
| + if (status != 0)
|
| + return false;
|
|
|
| buflen = buflen_;
|
|
|
| - pos += size_; // consume size of payload
|
| + pos += size; // consume size of payload
|
| return true;
|
| }
|
|
|
| -namespace mkvparser {
|
| -
|
| EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
|
|
|
| EBMLHeader::~EBMLHeader() { delete[] m_docType; }
|
| @@ -433,7 +494,8 @@ void EBMLHeader::Init() {
|
| }
|
|
|
| long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
|
| - assert(pReader);
|
| + if (!pReader)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| long long total, available;
|
|
|
| @@ -445,67 +507,45 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
|
| pos = 0;
|
| long long end = (available >= 1024) ? 1024 : available;
|
|
|
| - for (;;) {
|
| - unsigned char b = 0;
|
| -
|
| - while (pos < end) {
|
| - status = pReader->Read(pos, 1, &b);
|
| -
|
| - if (status < 0) // error
|
| - return status;
|
| -
|
| - if (b == 0x1A)
|
| - break;
|
| -
|
| - ++pos;
|
| - }
|
| -
|
| - if (b != 0x1A) {
|
| - if (pos >= 1024)
|
| - return E_FILE_FORMAT_INVALID; // don't bother looking anymore
|
| -
|
| - if ((total >= 0) && ((total - available) < 5))
|
| - return E_FILE_FORMAT_INVALID;
|
| -
|
| - return available + 5; // 5 = 4-byte ID + 1st byte of size
|
| - }
|
| -
|
| - if ((total >= 0) && ((total - pos) < 5))
|
| - return E_FILE_FORMAT_INVALID;
|
| -
|
| - if ((available - pos) < 5)
|
| - return pos + 5; // try again later
|
| -
|
| - long len;
|
| + // Scan until we find what looks like the first byte of the EBML header.
|
| + const int kMaxScanBytes = (available >= 1024) ? 1024 : available;
|
| + const unsigned char kEbmlByte0 = 0x1A;
|
| + unsigned char scan_byte = 0;
|
|
|
| - const long long result = ReadUInt(pReader, pos, len);
|
| + while (pos < kMaxScanBytes) {
|
| + status = pReader->Read(pos, 1, &scan_byte);
|
|
|
| - if (result < 0) // error
|
| - return result;
|
| + if (status < 0) // error
|
| + return status;
|
| + else if (status > 0)
|
| + return E_BUFFER_NOT_FULL;
|
|
|
| - if (result == 0x0A45DFA3) { // EBML Header ID
|
| - pos += len; // consume ID
|
| + if (scan_byte == kEbmlByte0)
|
| break;
|
| - }
|
|
|
| - ++pos; // throw away just the 0x1A byte, and try again
|
| + ++pos;
|
| }
|
|
|
| - // pos designates start of size field
|
| + long len = 0;
|
| + const long long ebml_id = ReadID(pReader, pos, len);
|
|
|
| - // get length of size field
|
| + // TODO(tomfinegan): Move Matroska ID constants into a common namespace.
|
| + if (len != 4 || ebml_id != mkvmuxer::kMkvEBML)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| - long len;
|
| + // Move read pos forward to the EBML header size field.
|
| + pos += 4;
|
| +
|
| + // Read length of size field.
|
| long long result = GetUIntLength(pReader, pos, len);
|
|
|
| if (result < 0) // error
|
| - return result;
|
| -
|
| - if (result > 0) // need more data
|
| - return result;
|
| + return E_FILE_FORMAT_INVALID;
|
| + else if (result > 0) // need more data
|
| + return E_BUFFER_NOT_FULL;
|
|
|
| - assert(len > 0);
|
| - assert(len <= 8);
|
| + if (len < 1 || len > 8)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if ((total >= 0) && ((total - pos) < len))
|
| return E_FILE_FORMAT_INVALID;
|
| @@ -513,8 +553,7 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
|
| if ((available - pos) < len)
|
| return pos + len; // try again later
|
|
|
| - // get the EBML header size
|
| -
|
| + // Read the EBML header size.
|
| result = ReadUInt(pReader, pos, len);
|
|
|
| if (result < 0) // error
|
| @@ -542,30 +581,30 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (size == 0) // weird
|
| + if (size == 0)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| - if (id == 0x0286) { // version
|
| + if (id == mkvmuxer::kMkvEBMLVersion) {
|
| m_version = UnserializeUInt(pReader, pos, size);
|
|
|
| if (m_version <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x02F7) { // read version
|
| + } else if (id == mkvmuxer::kMkvEBMLReadVersion) {
|
| m_readVersion = UnserializeUInt(pReader, pos, size);
|
|
|
| if (m_readVersion <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x02F2) { // max id length
|
| + } else if (id == mkvmuxer::kMkvEBMLMaxIDLength) {
|
| m_maxIdLength = UnserializeUInt(pReader, pos, size);
|
|
|
| if (m_maxIdLength <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x02F3) { // max size length
|
| + } else if (id == mkvmuxer::kMkvEBMLMaxSizeLength) {
|
| m_maxSizeLength = UnserializeUInt(pReader, pos, size);
|
|
|
| if (m_maxSizeLength <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x0282) { // doctype
|
| + } else if (id == mkvmuxer::kMkvDocType) {
|
| if (m_docType)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| @@ -573,12 +612,12 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
|
|
|
| if (status) // error
|
| return status;
|
| - } else if (id == 0x0287) { // doctype version
|
| + } else if (id == mkvmuxer::kMkvDocTypeVersion) {
|
| m_docTypeVersion = UnserializeUInt(pReader, pos, size);
|
|
|
| if (m_docTypeVersion <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x0285) { // doctype read version
|
| + } else if (id == mkvmuxer::kMkvDocTypeReadVersion) {
|
| m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
|
|
|
| if (m_docTypeReadVersion <= 0)
|
| @@ -588,7 +627,18 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
|
| pos += size;
|
| }
|
|
|
| - assert(pos == end);
|
| + if (pos != end)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| + // Make sure DocType, DocTypeReadVersion, and DocTypeVersion are valid.
|
| + if (m_docType == NULL || m_docTypeReadVersion <= 0 || m_docTypeVersion <= 0)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| + // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
|
| + if (m_maxIdLength <= 0 || m_maxIdLength > 4 ||
|
| + m_maxSizeLength <= 0 || m_maxSizeLength > 8)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| return 0;
|
| }
|
|
|
| @@ -621,8 +671,6 @@ Segment::~Segment() {
|
|
|
| while (i != j) {
|
| Cluster* const p = *i++;
|
| - assert(p);
|
| -
|
| delete p;
|
| }
|
|
|
| @@ -638,8 +686,8 @@ Segment::~Segment() {
|
|
|
| long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
|
| Segment*& pSegment) {
|
| - assert(pReader);
|
| - assert(pos >= 0);
|
| + if (pReader == NULL || pos < 0)
|
| + return E_PARSE_FAILED;
|
|
|
| pSegment = NULL;
|
|
|
| @@ -691,10 +739,10 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
|
| return pos + len;
|
|
|
| const long long idpos = pos;
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| + const long long id = ReadID(pReader, pos, len);
|
|
|
| - if (id < 0) // error
|
| - return id;
|
| + if (id < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| pos += len; // consume ID
|
|
|
| @@ -723,7 +771,7 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
|
| // Handle "unknown size" for live streaming of webm files.
|
| const long long unknown_size = (1LL << (7 * len)) - 1;
|
|
|
| - if (id == 0x08538067) { // Segment ID
|
| + if (id == mkvmuxer::kMkvSegment) {
|
| if (size == unknown_size)
|
| size = -1;
|
|
|
| @@ -733,12 +781,9 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
|
| else if ((pos + size) > total)
|
| size = -1;
|
|
|
| - pSegment = new (std::nothrow) Segment(pReader, idpos,
|
| - // elem_size
|
| - pos, size);
|
| -
|
| - if (pSegment == 0)
|
| - return -1; // generic error
|
| + pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
|
| + if (pSegment == NULL)
|
| + return E_PARSE_FAILED;
|
|
|
| return 0; // success
|
| }
|
| @@ -767,11 +812,15 @@ long long Segment::ParseHeaders() {
|
| if (status < 0) // error
|
| return status;
|
|
|
| - assert((total < 0) || (available <= total));
|
| + if (total > 0 && available > total)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
|
| - assert((segment_stop < 0) || (total < 0) || (segment_stop <= total));
|
| - assert((segment_stop < 0) || (m_pos <= segment_stop));
|
| +
|
| + if ((segment_stop >= 0 && total >= 0 && segment_stop > total) ||
|
| + (segment_stop >= 0 && m_pos > segment_stop)) {
|
| + return E_FILE_FORMAT_INVALID;
|
| + }
|
|
|
| for (;;) {
|
| if ((total >= 0) && (m_pos >= total))
|
| @@ -783,6 +832,11 @@ long long Segment::ParseHeaders() {
|
| long long pos = m_pos;
|
| const long long element_start = pos;
|
|
|
| + // Avoid rolling over pos when very close to LONG_LONG_MAX.
|
| + unsigned long long rollover_check = pos + 1ULL;
|
| + if (rollover_check > LONG_LONG_MAX)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| if ((pos + 1) > available)
|
| return (pos + 1);
|
|
|
| @@ -792,8 +846,10 @@ long long Segment::ParseHeaders() {
|
| if (result < 0) // error
|
| return result;
|
|
|
| - if (result > 0) // underflow (weird)
|
| + if (result > 0) {
|
| + // MkvReader doesn't have enough data to satisfy this read attempt.
|
| return (pos + 1);
|
| + }
|
|
|
| if ((segment_stop >= 0) && ((pos + len) > segment_stop))
|
| return E_FILE_FORMAT_INVALID;
|
| @@ -802,12 +858,12 @@ long long Segment::ParseHeaders() {
|
| return pos + len;
|
|
|
| const long long idpos = pos;
|
| - const long long id = ReadUInt(m_pReader, idpos, len);
|
| + const long long id = ReadID(m_pReader, idpos, len);
|
|
|
| - if (id < 0) // error
|
| - return id;
|
| + if (id < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| - if (id == 0x0F43B675) // Cluster ID
|
| + if (id == mkvmuxer::kMkvCluster)
|
| break;
|
|
|
| pos += len; // consume ID
|
| @@ -821,8 +877,10 @@ long long Segment::ParseHeaders() {
|
| if (result < 0) // error
|
| return result;
|
|
|
| - if (result > 0) // underflow (weird)
|
| + if (result > 0) {
|
| + // MkvReader doesn't have enough data to satisfy this read attempt.
|
| return (pos + 1);
|
| + }
|
|
|
| if ((segment_stop >= 0) && ((pos + len) > segment_stop))
|
| return E_FILE_FORMAT_INVALID;
|
| @@ -832,11 +890,19 @@ long long Segment::ParseHeaders() {
|
|
|
| const long long size = ReadUInt(m_pReader, pos, len);
|
|
|
| - if (size < 0) // error
|
| + if (size < 0 || len < 1 || len > 8) {
|
| + // TODO(tomfinegan): ReadUInt should return an error when len is < 1 or
|
| + // len > 8 is true instead of checking this _everywhere_.
|
| return size;
|
| + }
|
|
|
| pos += len; // consume length of size of element
|
|
|
| + // Avoid rolling over pos when very close to LONG_LONG_MAX.
|
| + rollover_check = static_cast<unsigned long long>(pos) + size;
|
| + if (rollover_check > LONG_LONG_MAX)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| const long long element_size = size + pos - element_start;
|
|
|
| // Pos now points to start of payload
|
| @@ -849,7 +915,7 @@ long long Segment::ParseHeaders() {
|
| if ((pos + size) > available)
|
| return pos + size;
|
|
|
| - if (id == 0x0549A966) { // Segment Info ID
|
| + if (id == mkvmuxer::kMkvInfo) {
|
| if (m_pInfo)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| @@ -863,7 +929,7 @@ long long Segment::ParseHeaders() {
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x0654AE6B) { // Tracks ID
|
| + } else if (id == mkvmuxer::kMkvTracks) {
|
| if (m_pTracks)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| @@ -877,7 +943,7 @@ long long Segment::ParseHeaders() {
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x0C53BB6B) { // Cues ID
|
| + } else if (id == mkvmuxer::kMkvCues) {
|
| if (m_pCues == NULL) {
|
| m_pCues = new (std::nothrow)
|
| Cues(this, pos, size, element_start, element_size);
|
| @@ -885,7 +951,7 @@ long long Segment::ParseHeaders() {
|
| if (m_pCues == NULL)
|
| return -1;
|
| }
|
| - } else if (id == 0x014D9B74) { // SeekHead ID
|
| + } else if (id == mkvmuxer::kMkvSeekHead) {
|
| if (m_pSeekHead == NULL) {
|
| m_pSeekHead = new (std::nothrow)
|
| SeekHead(this, pos, size, element_start, element_size);
|
| @@ -898,7 +964,7 @@ long long Segment::ParseHeaders() {
|
| if (status)
|
| return status;
|
| }
|
| - } else if (id == 0x0043A770) { // Chapters ID
|
| + } else if (id == mkvmuxer::kMkvChapters) {
|
| if (m_pChapters == NULL) {
|
| m_pChapters = new (std::nothrow)
|
| Chapters(this, pos, size, element_start, element_size);
|
| @@ -911,7 +977,7 @@ long long Segment::ParseHeaders() {
|
| if (status)
|
| return status;
|
| }
|
| - } else if (id == 0x0254C367) { // Tags ID
|
| + } else if (id == mkvmuxer::kMkvTags) {
|
| if (m_pTags == NULL) {
|
| m_pTags = new (std::nothrow)
|
| Tags(this, pos, size, element_start, element_size);
|
| @@ -929,7 +995,8 @@ long long Segment::ParseHeaders() {
|
| m_pos = pos + size; // consume payload
|
| }
|
|
|
| - assert((segment_stop < 0) || (m_pos <= segment_stop));
|
| + if (segment_stop >= 0 && m_pos > segment_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if (m_pInfo == NULL) // TODO: liberalize this behavior
|
| return E_FILE_FORMAT_INVALID;
|
| @@ -960,7 +1027,8 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| if (status < 0) // error
|
| return status;
|
|
|
| - assert((total < 0) || (avail <= total));
|
| + if (total >= 0 && avail > total)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
|
|
|
| @@ -988,7 +1056,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| if (result < 0) // error
|
| return static_cast<long>(result);
|
|
|
| - if (result > 0) // weird
|
| + if (result > 0)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| if ((segment_stop >= 0) && ((pos + len) > segment_stop))
|
| @@ -998,10 +1066,10 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| return E_BUFFER_NOT_FULL;
|
|
|
| const long long idpos = pos;
|
| - const long long id = ReadUInt(m_pReader, idpos, len);
|
| + const long long id = ReadID(m_pReader, idpos, len);
|
|
|
| - if (id < 0) // error (or underflow)
|
| - return static_cast<long>(id);
|
| + if (id < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| pos += len; // consume ID
|
|
|
| @@ -1017,7 +1085,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| if (result < 0) // error
|
| return static_cast<long>(result);
|
|
|
| - if (result > 0) // weird
|
| + if (result > 0)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| if ((segment_stop >= 0) && ((pos + len) > segment_stop))
|
| @@ -1035,7 +1103,8 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
|
|
| // pos now points to start of payload
|
|
|
| - if (size == 0) { // weird
|
| + if (size == 0) {
|
| + // Missing element payload: move on.
|
| m_pos = pos;
|
| continue;
|
| }
|
| @@ -1047,24 +1116,30 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - if (id == 0x0C53BB6B) { // Cues ID
|
| - if (size == unknown_size)
|
| - return E_FILE_FORMAT_INVALID; // TODO: liberalize
|
| + if (id == mkvmuxer::kMkvCues) {
|
| + if (size == unknown_size) {
|
| + // Cues element of unknown size: Not supported.
|
| + return E_FILE_FORMAT_INVALID;
|
| + }
|
|
|
| if (m_pCues == NULL) {
|
| const long long element_size = (pos - idpos) + size;
|
|
|
| - m_pCues = new Cues(this, pos, size, idpos, element_size);
|
| - assert(m_pCues); // TODO
|
| + m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
|
| + if (m_pCues == NULL)
|
| + return -1;
|
| }
|
|
|
| m_pos = pos + size; // consume payload
|
| continue;
|
| }
|
|
|
| - if (id != 0x0F43B675) { // Cluster ID
|
| + if (id != mkvmuxer::kMkvCluster) {
|
| + // Besides the Segment, Libwebm allows only cluster elements of unknown
|
| + // size. Fail the parse upon encountering a non-cluster element reporting
|
| + // unknown size.
|
| if (size == unknown_size)
|
| - return E_FILE_FORMAT_INVALID; // TODO: liberalize
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| m_pos = pos + size; // consume payload
|
| continue;
|
| @@ -1080,7 +1155,10 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| break;
|
| }
|
|
|
| - assert(cluster_off >= 0); // have cluster
|
| + if (cluster_off < 0) {
|
| + // No cluster, die.
|
| + return E_FILE_FORMAT_INVALID;
|
| + }
|
|
|
| long long pos_;
|
| long len_;
|
| @@ -1126,14 +1204,16 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| const long idx = m_clusterCount;
|
|
|
| if (m_clusterPreloadCount > 0) {
|
| - assert(idx < m_clusterSize);
|
| + if (idx >= m_clusterSize)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| Cluster* const pCluster = m_clusters[idx];
|
| - assert(pCluster);
|
| - assert(pCluster->m_index < 0);
|
| + if (pCluster == NULL || pCluster->m_index >= 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| const long long off = pCluster->GetPosition();
|
| - assert(off >= 0);
|
| + if (off < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if (off == cluster_off) { // preloaded already
|
| if (status == 0) // no entries found
|
| @@ -1155,7 +1235,8 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| --m_clusterPreloadCount;
|
|
|
| m_pos = pos; // consume payload
|
| - assert((segment_stop < 0) || (m_pos <= segment_stop));
|
| + if (segment_stop >= 0 && m_pos > segment_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| return 0; // success
|
| }
|
| @@ -1182,19 +1263,21 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| // status > 0 means we have an entry
|
|
|
| Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
|
| - // element_size);
|
| - assert(pCluster);
|
| + if (pCluster == NULL)
|
| + return -1;
|
|
|
| - AppendCluster(pCluster);
|
| - assert(m_clusters);
|
| - assert(idx < m_clusterSize);
|
| - assert(m_clusters[idx] == pCluster);
|
| + if (!AppendCluster(pCluster)) {
|
| + delete pCluster;
|
| + return -1;
|
| + }
|
|
|
| if (cluster_size >= 0) {
|
| pos += cluster_size;
|
|
|
| m_pos = pos;
|
| - assert((segment_stop < 0) || (m_pos <= segment_stop));
|
| +
|
| + if (segment_stop > 0 && m_pos > segment_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| return 0;
|
| }
|
| @@ -1210,8 +1293,8 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
| }
|
|
|
| long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
|
| - assert(m_pos < 0);
|
| - assert(m_pUnknownSize);
|
| + if (m_pos >= 0 || m_pUnknownSize == NULL)
|
| + return E_PARSE_FAILED;
|
|
|
| const long status = m_pUnknownSize->Parse(pos, len);
|
|
|
| @@ -1221,12 +1304,11 @@ long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
|
| if (status == 0) // parsed a block
|
| return 2; // continue parsing
|
|
|
| - assert(status > 0); // nothing left to parse of this cluster
|
| -
|
| const long long start = m_pUnknownSize->m_element_start;
|
| -
|
| const long long size = m_pUnknownSize->GetElementSize();
|
| - assert(size >= 0);
|
| +
|
| + if (size < 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| pos = start + size;
|
| m_pos = pos;
|
| @@ -1236,24 +1318,26 @@ long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
|
| return 2; // continue parsing
|
| }
|
|
|
| -void Segment::AppendCluster(Cluster* pCluster) {
|
| - assert(pCluster);
|
| - assert(pCluster->m_index >= 0);
|
| +bool Segment::AppendCluster(Cluster* pCluster) {
|
| + if (pCluster == NULL || pCluster->m_index < 0)
|
| + return false;
|
|
|
| const long count = m_clusterCount + m_clusterPreloadCount;
|
|
|
| long& size = m_clusterSize;
|
| - assert(size >= count);
|
| -
|
| const long idx = pCluster->m_index;
|
| - assert(idx == m_clusterCount);
|
| +
|
| + if (size < count || idx != m_clusterCount)
|
| + return false;
|
|
|
| if (count >= size) {
|
| const long n = (size <= 0) ? 2048 : 2 * size;
|
|
|
| - Cluster** const qq = new Cluster*[n];
|
| - Cluster** q = qq;
|
| + Cluster** const qq = new (std::nothrow) Cluster*[n];
|
| + if (qq == NULL)
|
| + return false;
|
|
|
| + Cluster** q = qq;
|
| Cluster** p = m_clusters;
|
| Cluster** const pp = p + count;
|
|
|
| @@ -1267,18 +1351,18 @@ void Segment::AppendCluster(Cluster* pCluster) {
|
| }
|
|
|
| if (m_clusterPreloadCount > 0) {
|
| - assert(m_clusters);
|
| -
|
| Cluster** const p = m_clusters + m_clusterCount;
|
| - assert(*p);
|
| - assert((*p)->m_index < 0);
|
| + if (*p == NULL || (*p)->m_index >= 0)
|
| + return false;
|
|
|
| Cluster** q = p + m_clusterPreloadCount;
|
| - assert(q < (m_clusters + size));
|
| + if (q >= (m_clusters + size))
|
| + return false;
|
|
|
| for (;;) {
|
| Cluster** const qq = q - 1;
|
| - assert((*qq)->m_index < 0);
|
| + if ((*qq)->m_index >= 0)
|
| + return false;
|
|
|
| *q = *qq;
|
| q = qq;
|
| @@ -1290,22 +1374,25 @@ void Segment::AppendCluster(Cluster* pCluster) {
|
|
|
| m_clusters[idx] = pCluster;
|
| ++m_clusterCount;
|
| + return true;
|
| }
|
|
|
| -void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
|
| - assert(pCluster);
|
| - assert(pCluster->m_index < 0);
|
| - assert(idx >= m_clusterCount);
|
| +bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
|
| + if (pCluster == NULL || pCluster->m_index >= 0 || idx < m_clusterCount)
|
| + return false;
|
|
|
| const long count = m_clusterCount + m_clusterPreloadCount;
|
|
|
| long& size = m_clusterSize;
|
| - assert(size >= count);
|
| + if (size < count)
|
| + return false;
|
|
|
| if (count >= size) {
|
| const long n = (size <= 0) ? 2048 : 2 * size;
|
|
|
| - Cluster** const qq = new Cluster*[n];
|
| + Cluster** const qq = new (std::nothrow) Cluster*[n];
|
| + if (qq == NULL)
|
| + return false;
|
| Cluster** q = qq;
|
|
|
| Cluster** p = m_clusters;
|
| @@ -1320,17 +1407,20 @@ void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
|
| size = n;
|
| }
|
|
|
| - assert(m_clusters);
|
| + if (m_clusters == NULL)
|
| + return false;
|
|
|
| Cluster** const p = m_clusters + idx;
|
|
|
| Cluster** q = m_clusters + count;
|
| - assert(q >= p);
|
| - assert(q < (m_clusters + size));
|
| + if (q < p || q >= (m_clusters + size))
|
| + return false;
|
|
|
| while (q > p) {
|
| Cluster** const qq = q - 1;
|
| - assert((*qq)->m_index < 0);
|
| +
|
| + if ((*qq)->m_index >= 0)
|
| + return false;
|
|
|
| *q = *qq;
|
| q = qq;
|
| @@ -1338,13 +1428,12 @@ void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
|
|
|
| m_clusters[idx] = pCluster;
|
| ++m_clusterPreloadCount;
|
| + return true;
|
| }
|
|
|
| long Segment::Load() {
|
| - assert(m_clusters == NULL);
|
| - assert(m_clusterSize == 0);
|
| - assert(m_clusterCount == 0);
|
| - // assert(m_size >= 0);
|
| + if (m_clusters != NULL || m_clusterSize != 0 || m_clusterCount != 0)
|
| + return E_PARSE_FAILED;
|
|
|
| // Outermost (level 0) segment object has been constructed,
|
| // and pos designates start of payload. We need to find the
|
| @@ -1358,8 +1447,8 @@ long Segment::Load() {
|
| if (header_status > 0) // underflow
|
| return E_BUFFER_NOT_FULL;
|
|
|
| - assert(m_pInfo);
|
| - assert(m_pTracks);
|
| + if (m_pInfo == NULL || m_pTracks == NULL)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| for (;;) {
|
| const int status = LoadCluster();
|
| @@ -1408,16 +1497,19 @@ long SeekHead::Parse() {
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x0DBB) // SeekEntry ID
|
| + if (id == mkvmuxer::kMkvSeek)
|
| ++entry_count;
|
| - else if (id == 0x6C) // Void ID
|
| + else if (id == mkvmuxer::kMkvVoid)
|
| ++void_element_count;
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| +
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| m_entries = new (std::nothrow) Entry[entry_count];
|
|
|
| @@ -1446,14 +1538,14 @@ long SeekHead::Parse() {
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x0DBB) { // SeekEntry ID
|
| + if (id == mkvmuxer::kMkvSeek) {
|
| if (ParseEntry(pReader, pos, size, pEntry)) {
|
| Entry& e = *pEntry++;
|
|
|
| e.element_start = idpos;
|
| e.element_size = (pos + size) - idpos;
|
| }
|
| - } else if (id == 0x6C) { // Void ID
|
| + } else if (id == mkvmuxer::kMkvVoid) {
|
| VoidElement& e = *pVoidElement++;
|
|
|
| e.element_start = idpos;
|
| @@ -1461,10 +1553,12 @@ long SeekHead::Parse() {
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
|
| assert(count_ >= 0);
|
| @@ -1553,9 +1647,9 @@ long Segment::ParseCues(long long off, long long& pos, long& len) {
|
|
|
| const long long idpos = pos;
|
|
|
| - const long long id = ReadUInt(m_pReader, idpos, len);
|
| + const long long id = ReadID(m_pReader, idpos, len);
|
|
|
| - if (id != 0x0C53BB6B) // Cues ID
|
| + if (id != mkvmuxer::kMkvCues)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| pos += len; // consume ID
|
| @@ -1615,7 +1709,8 @@ long Segment::ParseCues(long long off, long long& pos, long& len) {
|
|
|
| m_pCues =
|
| new (std::nothrow) Cues(this, pos, size, element_start, element_size);
|
| - assert(m_pCues); // TODO
|
| + if (m_pCues == NULL)
|
| + return -1;
|
|
|
| return 0; // success
|
| }
|
| @@ -1632,10 +1727,11 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
|
|
|
| // parse the container for the level-1 element ID
|
|
|
| - const long long seekIdId = ReadUInt(pReader, pos, len);
|
| - // seekIdId;
|
| + const long long seekIdId = ReadID(pReader, pos, len);
|
| + if (seekIdId < 0)
|
| + return false;
|
|
|
| - if (seekIdId != 0x13AB) // SeekID ID
|
| + if (seekIdId != mkvmuxer::kMkvSeekID)
|
| return false;
|
|
|
| if ((pos + len) > stop)
|
| @@ -1677,9 +1773,9 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
|
|
|
| pos += seekIdSize; // consume SeekID payload
|
|
|
| - const long long seekPosId = ReadUInt(pReader, pos, len);
|
| + const long long seekPosId = ReadID(pReader, pos, len);
|
|
|
| - if (seekPosId != 0x13AC) // SeekPos ID
|
| + if (seekPosId != mkvmuxer::kMkvSeekPosition)
|
| return false;
|
|
|
| if ((pos + len) > stop)
|
| @@ -1757,8 +1853,8 @@ bool Cues::Init() const {
|
| if (m_cue_points)
|
| return true;
|
|
|
| - assert(m_count == 0);
|
| - assert(m_preload_count == 0);
|
| + if (m_count != 0 || m_preload_count != 0)
|
| + return false;
|
|
|
| IMkvReader* const pReader = m_pSegment->m_pReader;
|
|
|
| @@ -1772,7 +1868,7 @@ bool Cues::Init() const {
|
|
|
| long len;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| + const long long id = ReadID(pReader, pos, len);
|
| if (id < 0 || (pos + len) > stop) {
|
| return false;
|
| }
|
| @@ -1789,21 +1885,27 @@ bool Cues::Init() const {
|
| return false;
|
| }
|
|
|
| - if (id == 0x3B) // CuePoint ID
|
| - PreloadCuePoint(cue_points_size, idpos);
|
| + if (id == mkvmuxer::kMkvCuePoint) {
|
| + if (!PreloadCuePoint(cue_points_size, idpos))
|
| + return false;
|
| + }
|
|
|
| pos += size; // skip payload
|
| }
|
| return true;
|
| }
|
|
|
| -void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
|
| - assert(m_count == 0);
|
| +bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
|
| + if (m_count != 0)
|
| + return false;
|
|
|
| if (m_preload_count >= cue_points_size) {
|
| const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
|
|
|
| - CuePoint** const qq = new CuePoint*[n];
|
| + CuePoint** const qq = new (std::nothrow) CuePoint*[n];
|
| + if (qq == NULL)
|
| + return false;
|
| +
|
| CuePoint** q = qq; // beginning of target
|
|
|
| CuePoint** p = m_cue_points; // beginning of source
|
| @@ -1818,14 +1920,15 @@ void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
|
| cue_points_size = n;
|
| }
|
|
|
| - CuePoint* const pCP = new CuePoint(m_preload_count, pos);
|
| + CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos);
|
| + if (pCP == NULL)
|
| + return false;
|
| +
|
| m_cue_points[m_preload_count++] = pCP;
|
| + return true;
|
| }
|
|
|
| bool Cues::LoadCuePoint() const {
|
| - // odbgstream os;
|
| - // os << "Cues::LoadCuePoint" << endl;
|
| -
|
| const long long stop = m_start + m_size;
|
|
|
| if (m_pos >= stop)
|
| @@ -1843,32 +1946,33 @@ bool Cues::LoadCuePoint() const {
|
|
|
| long len;
|
|
|
| - const long long id = ReadUInt(pReader, m_pos, len);
|
| - assert(id >= 0); // TODO
|
| - assert((m_pos + len) <= stop);
|
| + const long long id = ReadID(pReader, m_pos, len);
|
| + if (id < 0 || (m_pos + len) > stop)
|
| + return false;
|
|
|
| m_pos += len; // consume ID
|
|
|
| const long long size = ReadUInt(pReader, m_pos, len);
|
| - assert(size >= 0);
|
| - assert((m_pos + len) <= stop);
|
| + if (size < 0 || (m_pos + len) > stop)
|
| + return false;
|
|
|
| m_pos += len; // consume Size field
|
| - assert((m_pos + size) <= stop);
|
| + if ((m_pos + size) > stop)
|
| + return false;
|
|
|
| - if (id != 0x3B) { // CuePoint ID
|
| + if (id != mkvmuxer::kMkvCuePoint) {
|
| m_pos += size; // consume payload
|
| - assert(m_pos <= stop);
|
| + if (m_pos > stop)
|
| + return false;
|
|
|
| continue;
|
| }
|
|
|
| - assert(m_preload_count > 0);
|
| + if (m_preload_count < 1)
|
| + return false;
|
|
|
| CuePoint* const pCP = m_cue_points[m_count];
|
| - assert(pCP);
|
| - assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos));
|
| - if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos))
|
| + if (!pCP || (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)))
|
| return false;
|
|
|
| if (!pCP->Load(pReader)) {
|
| @@ -1879,24 +1983,18 @@ bool Cues::LoadCuePoint() const {
|
| --m_preload_count;
|
|
|
| m_pos += size; // consume payload
|
| - assert(m_pos <= stop);
|
| + if (m_pos > stop)
|
| + return false;
|
|
|
| return true; // yes, we loaded a cue point
|
| }
|
|
|
| - // return (m_pos < stop);
|
| return false; // no, we did not load a cue point
|
| }
|
|
|
| bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
|
| const CuePoint::TrackPosition*& pTP) const {
|
| - assert(time_ns >= 0);
|
| - assert(pTrack);
|
| -
|
| - if (m_cue_points == NULL)
|
| - return false;
|
| -
|
| - if (m_count == 0)
|
| + if (time_ns < 0 || pTrack == NULL || m_cue_points == NULL || m_count == 0)
|
| return false;
|
|
|
| CuePoint** const ii = m_cue_points;
|
| @@ -1906,7 +2004,8 @@ bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
|
| CuePoint** j = jj;
|
|
|
| pCP = *i;
|
| - assert(pCP);
|
| + if (pCP == NULL)
|
| + return false;
|
|
|
| if (time_ns <= pCP->GetTime(m_pSegment)) {
|
| pTP = pCP->Find(pTrack);
|
| @@ -1920,10 +2019,12 @@ bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
|
| //[j, jj) > time_ns
|
|
|
| CuePoint** const k = i + (j - i) / 2;
|
| - assert(k < jj);
|
| + if (k >= jj)
|
| + return false;
|
|
|
| CuePoint* const pCP = *k;
|
| - assert(pCP);
|
| + if (pCP == NULL)
|
| + return false;
|
|
|
| const long long t = pCP->GetTime(m_pSegment);
|
|
|
| @@ -1932,16 +2033,17 @@ bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
|
| else
|
| j = k;
|
|
|
| - assert(i <= j);
|
| + if (i > j)
|
| + return false;
|
| }
|
|
|
| - assert(i == j);
|
| - assert(i <= jj);
|
| - assert(i > ii);
|
| + if (i != j || i > jj || i <= ii)
|
| + return false;
|
|
|
| pCP = *--i;
|
| - assert(pCP);
|
| - assert(pCP->GetTime(m_pSegment) <= time_ns);
|
| +
|
| + if (pCP == NULL || pCP->GetTime(m_pSegment) > time_ns)
|
| + return false;
|
|
|
| // TODO: here and elsewhere, it's probably not correct to search
|
| // for the cue point with this time, and then search for a matching
|
| @@ -1956,55 +2058,50 @@ bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
|
| }
|
|
|
| const CuePoint* Cues::GetFirst() const {
|
| - if (m_cue_points == NULL)
|
| - return NULL;
|
| -
|
| - if (m_count == 0)
|
| + if (m_cue_points == NULL || m_count == 0)
|
| return NULL;
|
|
|
| CuePoint* const* const pp = m_cue_points;
|
| - assert(pp);
|
| + if (pp == NULL)
|
| + return NULL;
|
|
|
| CuePoint* const pCP = pp[0];
|
| - assert(pCP);
|
| - assert(pCP->GetTimeCode() >= 0);
|
| + if (pCP == NULL || pCP->GetTimeCode() < 0)
|
| + return NULL;
|
|
|
| return pCP;
|
| }
|
|
|
| const CuePoint* Cues::GetLast() const {
|
| - if (m_cue_points == NULL)
|
| - return NULL;
|
| -
|
| - if (m_count <= 0)
|
| + if (m_cue_points == NULL || m_count <= 0)
|
| return NULL;
|
|
|
| const long index = m_count - 1;
|
|
|
| CuePoint* const* const pp = m_cue_points;
|
| - assert(pp);
|
| + if (pp == NULL)
|
| + return NULL;
|
|
|
| CuePoint* const pCP = pp[index];
|
| - assert(pCP);
|
| - assert(pCP->GetTimeCode() >= 0);
|
| + if (pCP == NULL || pCP->GetTimeCode() < 0)
|
| + return NULL;
|
|
|
| return pCP;
|
| }
|
|
|
| const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
|
| - if (pCurr == NULL)
|
| + if (pCurr == NULL || pCurr->GetTimeCode() < 0 ||
|
| + m_cue_points == NULL || m_count < 1) {
|
| return NULL;
|
| -
|
| - assert(pCurr->GetTimeCode() >= 0);
|
| - assert(m_cue_points);
|
| - assert(m_count >= 1);
|
| + }
|
|
|
| long index = pCurr->m_index;
|
| - assert(index < m_count);
|
| + if (index >= m_count)
|
| + return NULL;
|
|
|
| CuePoint* const* const pp = m_cue_points;
|
| - assert(pp);
|
| - assert(pp[index] == pCurr);
|
| + if (pp == NULL || pp[index] != pCurr)
|
| + return NULL;
|
|
|
| ++index;
|
|
|
| @@ -2012,18 +2109,16 @@ const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
|
| return NULL;
|
|
|
| CuePoint* const pNext = pp[index];
|
| - assert(pNext);
|
| - assert(pNext->GetTimeCode() >= 0);
|
| +
|
| + if (pNext == NULL || pNext->GetTimeCode() < 0)
|
| + return NULL;
|
|
|
| return pNext;
|
| }
|
|
|
| const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
|
| const CuePoint::TrackPosition* pTP) const {
|
| - if (pCP == NULL)
|
| - return NULL;
|
| -
|
| - if (pTP == NULL)
|
| + if (pCP == NULL || pTP == NULL)
|
| return NULL;
|
|
|
| return m_pSegment->GetBlock(*pCP, *pTP);
|
| @@ -2070,11 +2165,15 @@ const BlockEntry* Segment::GetBlock(const CuePoint& cp,
|
| // assert(Cluster::HasBlockEntries(this, tp.m_pos));
|
|
|
| Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1);
|
| - assert(pCluster);
|
| + if (pCluster == NULL)
|
| + return NULL;
|
|
|
| const ptrdiff_t idx = i - m_clusters;
|
|
|
| - PreloadCluster(pCluster, idx);
|
| + if (!PreloadCluster(pCluster, idx)) {
|
| + delete pCluster;
|
| + return NULL;
|
| + }
|
| assert(m_clusters);
|
| assert(m_clusterPreloadCount > 0);
|
| assert(m_clusters[idx] == pCluster);
|
| @@ -2125,12 +2224,15 @@ const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
|
| // assert(Cluster::HasBlockEntries(this, tp.m_pos));
|
|
|
| Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
|
| - //-1);
|
| - assert(pCluster);
|
| + if (pCluster == NULL)
|
| + return NULL;
|
|
|
| const ptrdiff_t idx = i - m_clusters;
|
|
|
| - PreloadCluster(pCluster, idx);
|
| + if (!PreloadCluster(pCluster, idx)) {
|
| + delete pCluster;
|
| + return NULL;
|
| + }
|
| assert(m_clusters);
|
| assert(m_clusterPreloadCount > 0);
|
| assert(m_clusters[idx] == pCluster);
|
| @@ -2168,9 +2270,8 @@ bool CuePoint::Load(IMkvReader* pReader) {
|
| {
|
| long len;
|
|
|
| - const long long id = ReadUInt(pReader, pos_, len);
|
| - assert(id == 0x3B); // CuePoint ID
|
| - if (id != 0x3B)
|
| + const long long id = ReadID(pReader, pos_, len);
|
| + if (id != mkvmuxer::kMkvCuePoint)
|
| return false;
|
|
|
| pos_ += len; // consume ID
|
| @@ -2193,7 +2294,7 @@ bool CuePoint::Load(IMkvReader* pReader) {
|
| while (pos < stop) {
|
| long len;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| + const long long id = ReadID(pReader, pos, len);
|
| if ((id < 0) || (pos + len > stop)) {
|
| return false;
|
| }
|
| @@ -2210,10 +2311,10 @@ bool CuePoint::Load(IMkvReader* pReader) {
|
| return false;
|
| }
|
|
|
| - if (id == 0x33) // CueTime ID
|
| + if (id == mkvmuxer::kMkvCueTime)
|
| m_timecode = UnserializeUInt(pReader, pos, size);
|
|
|
| - else if (id == 0x37) // CueTrackPosition(s) ID
|
| + else if (id == mkvmuxer::kMkvCueTrackPositions)
|
| ++m_track_positions_count;
|
|
|
| pos += size; // consume payload
|
| @@ -2227,7 +2328,9 @@ bool CuePoint::Load(IMkvReader* pReader) {
|
| // << " timecode=" << m_timecode
|
| // << endl;
|
|
|
| - m_track_positions = new TrackPosition[m_track_positions_count];
|
| + m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count];
|
| + if (m_track_positions == NULL)
|
| + return false;
|
|
|
| // Now parse track positions
|
|
|
| @@ -2237,9 +2340,9 @@ bool CuePoint::Load(IMkvReader* pReader) {
|
| while (pos < stop) {
|
| long len;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| - assert(id >= 0);
|
| - assert((pos + len) <= stop);
|
| + const long long id = ReadID(pReader, pos, len);
|
| + if (id < 0 || (pos + len) > stop)
|
| + return false;
|
|
|
| pos += len; // consume ID
|
|
|
| @@ -2250,7 +2353,7 @@ bool CuePoint::Load(IMkvReader* pReader) {
|
| pos += len; // consume Size field
|
| assert((pos + size) <= stop);
|
|
|
| - if (id == 0x37) { // CueTrackPosition(s) ID
|
| + if (id == mkvmuxer::kMkvCueTrackPositions) {
|
| TrackPosition& tp = *p++;
|
| if (!tp.Parse(pReader, pos, size)) {
|
| return false;
|
| @@ -2258,7 +2361,8 @@ bool CuePoint::Load(IMkvReader* pReader) {
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return false;
|
| }
|
|
|
| assert(size_t(p - m_track_positions) == m_track_positions_count);
|
| @@ -2281,7 +2385,7 @@ bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
|
| while (pos < stop) {
|
| long len;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| + const long long id = ReadID(pReader, pos, len);
|
| if ((id < 0) || ((pos + len) > stop)) {
|
| return false;
|
| }
|
| @@ -2298,13 +2402,11 @@ bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
|
| return false;
|
| }
|
|
|
| - if (id == 0x77) // CueTrack ID
|
| + if (id == mkvmuxer::kMkvCueTrack)
|
| m_track = UnserializeUInt(pReader, pos, size);
|
| -
|
| - else if (id == 0x71) // CueClusterPos ID
|
| + else if (id == mkvmuxer::kMkvCueClusterPosition)
|
| m_pos = UnserializeUInt(pReader, pos, size);
|
| -
|
| - else if (id == 0x1378) // CueBlockNumber
|
| + else if (id == mkvmuxer::kMkvCueBlockNumber)
|
| m_block = UnserializeUInt(pReader, pos, size);
|
|
|
| pos += size; // consume payload
|
| @@ -2437,9 +2539,8 @@ const Cluster* Segment::GetNext(const Cluster* pCurr) {
|
| if (result != 0)
|
| return NULL;
|
|
|
| - const long long id = ReadUInt(m_pReader, pos, len);
|
| - assert(id == 0x0F43B675); // Cluster ID
|
| - if (id != 0x0F43B675)
|
| + const long long id = ReadID(m_pReader, pos, len);
|
| + if (id != mkvmuxer::kMkvCluster)
|
| return NULL;
|
|
|
| pos += len; // consume ID
|
| @@ -2474,8 +2575,9 @@ const Cluster* Segment::GetNext(const Cluster* pCurr) {
|
|
|
| const long long idpos = pos; // pos of next (potential) cluster
|
|
|
| - const long long id = ReadUInt(m_pReader, idpos, len);
|
| - assert(id > 0); // TODO
|
| + const long long id = ReadID(m_pReader, idpos, len);
|
| + if (id < 0)
|
| + return NULL;
|
|
|
| pos += len; // consume ID
|
|
|
| @@ -2495,7 +2597,7 @@ const Cluster* Segment::GetNext(const Cluster* pCurr) {
|
| if (size == 0) // weird
|
| continue;
|
|
|
| - if (id == 0x0F43B675) { // Cluster ID
|
| + if (id == mkvmuxer::kMkvCluster) {
|
| const long long off_next_ = idpos - m_start;
|
|
|
| long long pos_;
|
| @@ -2553,11 +2655,15 @@ const Cluster* Segment::GetNext(const Cluster* pCurr) {
|
| assert(i == j);
|
|
|
| Cluster* const pNext = Cluster::Create(this, -1, off_next);
|
| - assert(pNext);
|
| + if (pNext == NULL)
|
| + return NULL;
|
|
|
| const ptrdiff_t idx_next = i - m_clusters; // insertion position
|
|
|
| - PreloadCluster(pNext, idx_next);
|
| + if (!PreloadCluster(pNext, idx_next)) {
|
| + delete pNext;
|
| + return NULL;
|
| + }
|
| assert(m_clusters);
|
| assert(idx_next < m_clusterSize);
|
| assert(m_clusters[idx_next] == pNext);
|
| @@ -2641,7 +2747,7 @@ long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
|
|
|
| const long long id = ReadUInt(m_pReader, pos, len);
|
|
|
| - if (id != 0x0F43B675) // weird: not Cluster ID
|
| + if (id != mkvmuxer::kMkvCluster)
|
| return -1;
|
|
|
| pos += len; // consume ID
|
| @@ -2687,7 +2793,8 @@ long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
|
| // Pos now points to start of payload
|
|
|
| pos += size; // consume payload (that is, the current cluster)
|
| - assert((segment_stop < 0) || (pos <= segment_stop));
|
| + if (segment_stop >= 0 && pos > segment_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| // By consuming the payload, we are assuming that the curr
|
| // cluster isn't interesting. That is, we don't bother checking
|
| @@ -2755,7 +2862,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
| const long long idpos = pos; // absolute
|
| const long long idoff = pos - m_start; // relative
|
|
|
| - const long long id = ReadUInt(m_pReader, idpos, len); // absolute
|
| + const long long id = ReadID(m_pReader, idpos, len); // absolute
|
|
|
| if (id < 0) // error
|
| return static_cast<long>(id);
|
| @@ -2805,7 +2912,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
| return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - if (id == 0x0C53BB6B) { // Cues ID
|
| + if (id == mkvmuxer::kMkvCues) {
|
| if (size == unknown_size)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| @@ -2818,22 +2925,26 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
| const long long element_size = element_stop - element_start;
|
|
|
| if (m_pCues == NULL) {
|
| - m_pCues = new Cues(this, pos, size, element_start, element_size);
|
| - assert(m_pCues); // TODO
|
| + m_pCues = new (std::nothrow)
|
| + Cues(this, pos, size, element_start, element_size);
|
| + if (m_pCues == NULL)
|
| + return false;
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert((segment_stop < 0) || (pos <= segment_stop));
|
| + if (segment_stop >= 0 && pos > segment_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| continue;
|
| }
|
|
|
| - if (id != 0x0F43B675) { // not a Cluster ID
|
| + if (id != mkvmuxer::kMkvCluster) { // not a Cluster ID
|
| if (size == unknown_size)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| pos += size; // consume payload
|
| - assert((segment_stop < 0) || (pos <= segment_stop));
|
| + if (segment_stop >= 0 && pos > segment_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| continue;
|
| }
|
| @@ -2905,12 +3016,15 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
| Cluster* const pNext = Cluster::Create(this,
|
| -1, // preloaded
|
| off_next);
|
| - // element_size);
|
| - assert(pNext);
|
| + if (pNext == NULL)
|
| + return -1;
|
|
|
| const ptrdiff_t idx_next = i - m_clusters; // insertion position
|
|
|
| - PreloadCluster(pNext, idx_next);
|
| + if (!PreloadCluster(pNext, idx_next)) {
|
| + delete pNext;
|
| + return -1;
|
| + }
|
| assert(m_clusters);
|
| assert(idx_next < m_clusterSize);
|
| assert(m_clusters[idx_next] == pNext);
|
| @@ -2953,7 +3067,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
| return E_BUFFER_NOT_FULL;
|
|
|
| const long long idpos = pos;
|
| - const long long id = ReadUInt(m_pReader, idpos, len);
|
| + const long long id = ReadID(m_pReader, idpos, len);
|
|
|
| if (id < 0) // error (or underflow)
|
| return static_cast<long>(id);
|
| @@ -2962,10 +3076,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
| // that we have exhausted the sub-element's inside the cluster
|
| // whose ID we parsed earlier.
|
|
|
| - if (id == 0x0F43B675) // Cluster ID
|
| - break;
|
| -
|
| - if (id == 0x0C53BB6B) // Cues ID
|
| + if (id == mkvmuxer::kMkvCluster || id == mkvmuxer::kMkvCues)
|
| break;
|
|
|
| pos += len; // consume ID (of sub-element)
|
| @@ -3012,7 +3123,8 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| pos += size; // consume payload of sub-element
|
| - assert((segment_stop < 0) || (pos <= segment_stop));
|
| + if (segment_stop >= 0 && pos > segment_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| } // determine cluster size
|
|
|
| cluster_size = pos - payload_pos;
|
| @@ -3022,7 +3134,8 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
| }
|
|
|
| pos += cluster_size; // consume payload
|
| - assert((segment_stop < 0) || (pos <= segment_stop));
|
| + if (segment_stop >= 0 && pos > segment_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| return 2; // try to find a cluster that follows next
|
| }
|
| @@ -3131,7 +3244,7 @@ long Chapters::Parse() {
|
| if (size == 0) // weird
|
| continue;
|
|
|
| - if (id == 0x05B9) { // EditionEntry ID
|
| + if (id == mkvmuxer::kMkvEditionEntry) {
|
| status = ParseEdition(pos, size);
|
|
|
| if (status < 0) // error
|
| @@ -3139,10 +3252,12 @@ long Chapters::Parse() {
|
| }
|
|
|
| pos += size;
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| return 0;
|
| }
|
|
|
| @@ -3242,10 +3357,10 @@ long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (size == 0) // weird
|
| + if (size == 0)
|
| continue;
|
|
|
| - if (id == 0x36) { // Atom ID
|
| + if (id == mkvmuxer::kMkvChapterAtom) {
|
| status = ParseAtom(pReader, pos, size);
|
|
|
| if (status < 0) // error
|
| @@ -3253,10 +3368,12 @@ long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
|
| }
|
|
|
| pos += size;
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| return 0;
|
| }
|
|
|
| @@ -3373,20 +3490,20 @@ long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (size == 0) // weird
|
| + if (size == 0) // 0 length payload, skip.
|
| continue;
|
|
|
| - if (id == 0x00) { // Display ID
|
| + if (id == mkvmuxer::kMkvChapterDisplay) {
|
| status = ParseDisplay(pReader, pos, size);
|
|
|
| if (status < 0) // error
|
| return status;
|
| - } else if (id == 0x1654) { // StringUID ID
|
| + } else if (id == mkvmuxer::kMkvChapterStringUID) {
|
| status = UnserializeString(pReader, pos, size, m_string_uid);
|
|
|
| if (status < 0) // error
|
| return status;
|
| - } else if (id == 0x33C4) { // UID ID
|
| + } else if (id == mkvmuxer::kMkvChapterUID) {
|
| long long val;
|
| status = UnserializeInt(pReader, pos, size, val);
|
|
|
| @@ -3394,14 +3511,14 @@ long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
|
| return status;
|
|
|
| m_uid = static_cast<unsigned long long>(val);
|
| - } else if (id == 0x11) { // TimeStart ID
|
| + } else if (id == mkvmuxer::kMkvChapterTimeStart) {
|
| const long long val = UnserializeUInt(pReader, pos, size);
|
|
|
| if (val < 0) // error
|
| return static_cast<long>(val);
|
|
|
| m_start_timecode = val;
|
| - } else if (id == 0x12) { // TimeEnd ID
|
| + } else if (id == mkvmuxer::kMkvChapterTimeEnd) {
|
| const long long val = UnserializeUInt(pReader, pos, size);
|
|
|
| if (val < 0) // error
|
| @@ -3411,10 +3528,12 @@ long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
|
| }
|
|
|
| pos += size;
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| return 0;
|
| }
|
|
|
| @@ -3524,20 +3643,20 @@ long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (size == 0) // weird
|
| + if (size == 0) // No payload.
|
| continue;
|
|
|
| - if (id == 0x05) { // ChapterString ID
|
| + if (id == mkvmuxer::kMkvChapString) {
|
| status = UnserializeString(pReader, pos, size, m_string);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x037C) { // ChapterLanguage ID
|
| + } else if (id == mkvmuxer::kMkvChapLanguage) {
|
| status = UnserializeString(pReader, pos, size, m_language);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x037E) { // ChapterCountry ID
|
| + } else if (id == mkvmuxer::kMkvChapCountry) {
|
| status = UnserializeString(pReader, pos, size, m_country);
|
|
|
| if (status)
|
| @@ -3545,10 +3664,12 @@ long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
|
| }
|
|
|
| pos += size;
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| return 0;
|
| }
|
|
|
| @@ -3588,7 +3709,7 @@ long Tags::Parse() {
|
| if (size == 0) // 0 length tag, read another
|
| continue;
|
|
|
| - if (id == 0x3373) { // Tag ID
|
| + if (id == mkvmuxer::kMkvTag) {
|
| status = ParseTag(pos, size);
|
|
|
| if (status < 0)
|
| @@ -3596,14 +3717,12 @@ long Tags::Parse() {
|
| }
|
|
|
| pos += size;
|
| - assert(pos <= stop);
|
| if (pos > stop)
|
| - return -1;
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| if (pos != stop)
|
| - return -1;
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| return 0;
|
| }
|
| @@ -3706,7 +3825,7 @@ long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
|
| if (size == 0) // 0 length tag, read another
|
| continue;
|
|
|
| - if (id == 0x27C8) { // SimpleTag ID
|
| + if (id == mkvmuxer::kMkvSimpleTag) {
|
| status = ParseSimpleTag(pReader, pos, size);
|
|
|
| if (status < 0)
|
| @@ -3714,14 +3833,12 @@ long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
|
| }
|
|
|
| pos += size;
|
| - assert(pos <= stop);
|
| if (pos > stop)
|
| - return -1;
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| if (pos != stop)
|
| - return -1;
|
| + return E_FILE_FORMAT_INVALID;
|
| return 0;
|
| }
|
|
|
| @@ -3799,12 +3916,12 @@ long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
|
| if (size == 0) // weird
|
| continue;
|
|
|
| - if (id == 0x5A3) { // TagName ID
|
| + if (id == mkvmuxer::kMkvTagName) {
|
| status = UnserializeString(pReader, pos, size, m_tag_name);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x487) { // TagString ID
|
| + } else if (id == mkvmuxer::kMkvTagString) {
|
| status = UnserializeString(pReader, pos, size, m_tag_string);
|
|
|
| if (status)
|
| @@ -3812,14 +3929,12 @@ long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
|
| }
|
|
|
| pos += size;
|
| - assert(pos <= stop);
|
| if (pos > stop)
|
| - return -1;
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| if (pos != stop)
|
| - return -1;
|
| + return E_FILE_FORMAT_INVALID;
|
| return 0;
|
| }
|
|
|
| @@ -3866,12 +3981,12 @@ long SegmentInfo::Parse() {
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x0AD7B1) { // Timecode Scale
|
| + if (id == mkvmuxer::kMkvTimecodeScale) {
|
| m_timecodeScale = UnserializeUInt(pReader, pos, size);
|
|
|
| if (m_timecodeScale <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x0489) { // Segment duration
|
| + } else if (id == mkvmuxer::kMkvDuration) {
|
| const long status = UnserializeFloat(pReader, pos, size, m_duration);
|
|
|
| if (status < 0)
|
| @@ -3879,19 +3994,19 @@ long SegmentInfo::Parse() {
|
|
|
| if (m_duration < 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x0D80) { // MuxingApp
|
| + } else if (id == mkvmuxer::kMkvMuxingApp) {
|
| const long status =
|
| UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x1741) { // WritingApp
|
| + } else if (id == mkvmuxer::kMkvWritingApp) {
|
| const long status =
|
| UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x3BA9) { // Title
|
| + } else if (id == mkvmuxer::kMkvTitle) {
|
| const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
|
|
|
| if (status)
|
| @@ -3899,10 +4014,17 @@ long SegmentInfo::Parse() {
|
| }
|
|
|
| pos += size;
|
| - assert(pos <= stop);
|
| +
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + const double rollover_check = m_duration * m_timecodeScale;
|
| + if (rollover_check > LONG_LONG_MAX)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| return 0;
|
| }
|
| @@ -4039,15 +4161,15 @@ long ContentEncoding::ParseContentEncAESSettingsEntry(
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x7E8) {
|
| - // AESSettingsCipherMode
|
| + if (id == mkvmuxer::kMkvAESSettingsCipherMode) {
|
| aes->cipher_mode = UnserializeUInt(pReader, pos, size);
|
| if (aes->cipher_mode != 1)
|
| return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| return 0;
|
| @@ -4070,14 +4192,15 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x1034) // ContentCompression ID
|
| + if (id == mkvmuxer::kMkvContentCompression)
|
| ++compression_count;
|
|
|
| - if (id == 0x1035) // ContentEncryption ID
|
| + if (id == mkvmuxer::kMkvContentEncryption)
|
| ++encryption_count;
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| if (compression_count <= 0 && encryption_count <= 0)
|
| @@ -4108,19 +4231,15 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x1031) {
|
| - // ContentEncodingOrder
|
| + if (id == mkvmuxer::kMkvContentEncodingOrder) {
|
| encoding_order_ = UnserializeUInt(pReader, pos, size);
|
| - } else if (id == 0x1032) {
|
| - // ContentEncodingScope
|
| + } else if (id == mkvmuxer::kMkvContentEncodingScope) {
|
| encoding_scope_ = UnserializeUInt(pReader, pos, size);
|
| if (encoding_scope_ < 1)
|
| return -1;
|
| - } else if (id == 0x1033) {
|
| - // ContentEncodingType
|
| + } else if (id == mkvmuxer::kMkvContentEncodingType) {
|
| encoding_type_ = UnserializeUInt(pReader, pos, size);
|
| - } else if (id == 0x1034) {
|
| - // ContentCompression ID
|
| + } else if (id == mkvmuxer::kMkvContentCompression) {
|
| ContentCompression* const compression =
|
| new (std::nothrow) ContentCompression();
|
| if (!compression)
|
| @@ -4132,8 +4251,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
|
| return status;
|
| }
|
| *compression_entries_end_++ = compression;
|
| - } else if (id == 0x1035) {
|
| - // ContentEncryption ID
|
| + } else if (id == mkvmuxer::kMkvContentEncryption) {
|
| ContentEncryption* const encryption =
|
| new (std::nothrow) ContentEncryption();
|
| if (!encryption)
|
| @@ -4148,10 +4266,12 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| return 0;
|
| }
|
|
|
| @@ -4172,21 +4292,18 @@ long ContentEncoding::ParseCompressionEntry(long long start, long long size,
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x254) {
|
| - // ContentCompAlgo
|
| + if (id == mkvmuxer::kMkvContentCompAlgo) {
|
| long long algo = UnserializeUInt(pReader, pos, size);
|
| if (algo < 0)
|
| return E_FILE_FORMAT_INVALID;
|
| compression->algo = algo;
|
| valid = true;
|
| - } else if (id == 0x255) {
|
| - // ContentCompSettings
|
| + } else if (id == mkvmuxer::kMkvContentCompSettings) {
|
| if (size <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| const size_t buflen = static_cast<size_t>(size);
|
| - typedef unsigned char* buf_t;
|
| - const buf_t buf = new (std::nothrow) unsigned char[buflen];
|
| + unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
|
| if (buf == NULL)
|
| return -1;
|
|
|
| @@ -4202,7 +4319,8 @@ long ContentEncoding::ParseCompressionEntry(long long start, long long size,
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| // ContentCompAlgo is mandatory
|
| @@ -4227,13 +4345,11 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x7E1) {
|
| - // ContentEncAlgo
|
| + if (id == mkvmuxer::kMkvContentEncAlgo) {
|
| encryption->algo = UnserializeUInt(pReader, pos, size);
|
| if (encryption->algo != 5)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x7E2) {
|
| - // ContentEncKeyID
|
| + } else if (id == mkvmuxer::kMkvContentEncKeyID) {
|
| delete[] encryption->key_id;
|
| encryption->key_id = NULL;
|
| encryption->key_id_len = 0;
|
| @@ -4242,8 +4358,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| const size_t buflen = static_cast<size_t>(size);
|
| - typedef unsigned char* buf_t;
|
| - const buf_t buf = new (std::nothrow) unsigned char[buflen];
|
| + unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
|
| if (buf == NULL)
|
| return -1;
|
|
|
| @@ -4256,8 +4371,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
|
|
|
| encryption->key_id = buf;
|
| encryption->key_id_len = buflen;
|
| - } else if (id == 0x7E3) {
|
| - // ContentSignature
|
| + } else if (id == mkvmuxer::kMkvContentSignature) {
|
| delete[] encryption->signature;
|
| encryption->signature = NULL;
|
| encryption->signature_len = 0;
|
| @@ -4266,8 +4380,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| const size_t buflen = static_cast<size_t>(size);
|
| - typedef unsigned char* buf_t;
|
| - const buf_t buf = new (std::nothrow) unsigned char[buflen];
|
| + unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
|
| if (buf == NULL)
|
| return -1;
|
|
|
| @@ -4280,8 +4393,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
|
|
|
| encryption->signature = buf;
|
| encryption->signature_len = buflen;
|
| - } else if (id == 0x7E4) {
|
| - // ContentSigKeyID
|
| + } else if (id == mkvmuxer::kMkvContentSigKeyID) {
|
| delete[] encryption->sig_key_id;
|
| encryption->sig_key_id = NULL;
|
| encryption->sig_key_id_len = 0;
|
| @@ -4290,8 +4402,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| const size_t buflen = static_cast<size_t>(size);
|
| - typedef unsigned char* buf_t;
|
| - const buf_t buf = new (std::nothrow) unsigned char[buflen];
|
| + unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
|
| if (buf == NULL)
|
| return -1;
|
|
|
| @@ -4304,14 +4415,11 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
|
|
|
| encryption->sig_key_id = buf;
|
| encryption->sig_key_id_len = buflen;
|
| - } else if (id == 0x7E5) {
|
| - // ContentSigAlgo
|
| + } else if (id == mkvmuxer::kMkvContentSigAlgo) {
|
| encryption->sig_algo = UnserializeUInt(pReader, pos, size);
|
| - } else if (id == 0x7E6) {
|
| - // ContentSigHashAlgo
|
| + } else if (id == mkvmuxer::kMkvContentSigHashAlgo) {
|
| encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
|
| - } else if (id == 0x7E7) {
|
| - // ContentEncAESSettings
|
| + } else if (id == mkvmuxer::kMkvContentEncAESSettings) {
|
| const long status = ParseContentEncAESSettingsEntry(
|
| pos, size, pReader, &encryption->aes_settings);
|
| if (status)
|
| @@ -4319,7 +4427,8 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| return 0;
|
| @@ -4418,7 +4527,7 @@ int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
|
|
|
| const size_t len = strlen(src);
|
|
|
| - dst = new (std::nothrow) char[len + 1];
|
| + dst = SafeArrayAlloc<char>(1, len + 1);
|
|
|
| if (dst == NULL)
|
| return -1;
|
| @@ -4469,7 +4578,7 @@ int Track::Info::Copy(Info& dst) const {
|
| if (dst.codecPrivateSize != 0)
|
| return -1;
|
|
|
| - dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize];
|
| + dst.codecPrivate = SafeArrayAlloc<unsigned char>(1, codecPrivateSize);
|
|
|
| if (dst.codecPrivate == NULL)
|
| return -1;
|
| @@ -4797,11 +4906,12 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
|
| return status;
|
|
|
| // pos now designates start of element
|
| - if (id == 0x2240) // ContentEncoding ID
|
| + if (id == mkvmuxer::kMkvContentEncoding)
|
| ++count;
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| if (count <= 0)
|
| @@ -4821,7 +4931,7 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
|
| return status;
|
|
|
| // pos now designates start of element
|
| - if (id == 0x2240) { // ContentEncoding ID
|
| + if (id == mkvmuxer::kMkvContentEncoding) {
|
| ContentEncoding* const content_encoding =
|
| new (std::nothrow) ContentEncoding();
|
| if (!content_encoding)
|
| @@ -4837,10 +4947,12 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| return 0;
|
| }
|
| @@ -4892,37 +5004,37 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x30) { // pixel width
|
| + if (id == mkvmuxer::kMkvPixelWidth) {
|
| width = UnserializeUInt(pReader, pos, size);
|
|
|
| if (width <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x3A) { // pixel height
|
| + } else if (id == mkvmuxer::kMkvPixelHeight) {
|
| height = UnserializeUInt(pReader, pos, size);
|
|
|
| if (height <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x14B0) { // display width
|
| + } else if (id == mkvmuxer::kMkvDisplayWidth) {
|
| display_width = UnserializeUInt(pReader, pos, size);
|
|
|
| if (display_width <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x14BA) { // display height
|
| + } else if (id == mkvmuxer::kMkvDisplayHeight) {
|
| display_height = UnserializeUInt(pReader, pos, size);
|
|
|
| if (display_height <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x14B2) { // display unit
|
| + } else if (id == mkvmuxer::kMkvDisplayUnit) {
|
| display_unit = UnserializeUInt(pReader, pos, size);
|
|
|
| if (display_unit < 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x13B8) { // stereo mode
|
| + } else if (id == mkvmuxer::kMkvStereoMode) {
|
| stereo_mode = UnserializeUInt(pReader, pos, size);
|
|
|
| if (stereo_mode < 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x0383E3) { // frame rate
|
| + } else if (id == mkvmuxer::kMkvFrameRate) {
|
| const long status = UnserializeFloat(pReader, pos, size, rate);
|
|
|
| if (status < 0)
|
| @@ -4933,10 +5045,12 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| VideoTrack* const pTrack =
|
| new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
|
| @@ -5110,7 +5224,7 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
|
| if (status < 0) // error
|
| return status;
|
|
|
| - if (id == 0x35) { // Sample Rate
|
| + if (id == mkvmuxer::kMkvSamplingFrequency) {
|
| status = UnserializeFloat(pReader, pos, size, rate);
|
|
|
| if (status < 0)
|
| @@ -5118,12 +5232,12 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
|
|
|
| if (rate <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x1F) { // Channel Count
|
| + } else if (id == mkvmuxer::kMkvChannels) {
|
| channels = UnserializeUInt(pReader, pos, size);
|
|
|
| if (channels <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x2264) { // Bit Depth
|
| + } else if (id == mkvmuxer::kMkvBitDepth) {
|
| bit_depth = UnserializeUInt(pReader, pos, size);
|
|
|
| if (bit_depth <= 0)
|
| @@ -5131,10 +5245,12 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| AudioTrack* const pTrack =
|
| new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
|
| @@ -5194,14 +5310,16 @@ long Tracks::Parse() {
|
| if (size == 0) // weird
|
| continue;
|
|
|
| - if (id == 0x2E) // TrackEntry ID
|
| + if (id == mkvmuxer::kMkvTrackEntry)
|
| ++count;
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if (count <= 0)
|
| return 0; // success
|
| @@ -5234,13 +5352,12 @@ long Tracks::Parse() {
|
|
|
| const long long element_size = payload_stop - element_start;
|
|
|
| - if (id == 0x2E) { // TrackEntry ID
|
| + if (id == mkvmuxer::kMkvTrackEntry) {
|
| Track*& pTrack = *m_trackEntriesEnd;
|
| pTrack = NULL;
|
|
|
| const long status = ParseTrackEntry(pos, payload_size, element_start,
|
| element_size, pTrack);
|
| -
|
| if (status)
|
| return status;
|
|
|
| @@ -5249,10 +5366,12 @@ long Tracks::Parse() {
|
| }
|
|
|
| pos = payload_stop;
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| return 0; // success
|
| }
|
| @@ -5309,16 +5428,16 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
|
|
|
| const long long start = pos;
|
|
|
| - if (id == 0x60) { // VideoSettings ID
|
| + if (id == mkvmuxer::kMkvVideo) {
|
| v.start = start;
|
| v.size = size;
|
| - } else if (id == 0x61) { // AudioSettings ID
|
| + } else if (id == mkvmuxer::kMkvAudio) {
|
| a.start = start;
|
| a.size = size;
|
| - } else if (id == 0x2D80) { // ContentEncodings ID
|
| + } else if (id == mkvmuxer::kMkvContentEncodings) {
|
| e.start = start;
|
| e.size = size;
|
| - } else if (id == 0x33C5) { // Track UID
|
| + } else if (id == mkvmuxer::kMkvTrackUID) {
|
| if (size > 8)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| @@ -5340,49 +5459,49 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
|
|
|
| ++pos_;
|
| }
|
| - } else if (id == 0x57) { // Track Number
|
| + } else if (id == mkvmuxer::kMkvTrackNumber) {
|
| const long long num = UnserializeUInt(pReader, pos, size);
|
|
|
| if ((num <= 0) || (num > 127))
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| info.number = static_cast<long>(num);
|
| - } else if (id == 0x03) { // Track Type
|
| + } else if (id == mkvmuxer::kMkvTrackType) {
|
| const long long type = UnserializeUInt(pReader, pos, size);
|
|
|
| if ((type <= 0) || (type > 254))
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| info.type = static_cast<long>(type);
|
| - } else if (id == 0x136E) { // Track Name
|
| + } else if (id == mkvmuxer::kMkvName) {
|
| const long status =
|
| UnserializeString(pReader, pos, size, info.nameAsUTF8);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x02B59C) { // Track Language
|
| + } else if (id == mkvmuxer::kMkvLanguage) {
|
| const long status = UnserializeString(pReader, pos, size, info.language);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x03E383) { // Default Duration
|
| + } else if (id == mkvmuxer::kMkvDefaultDuration) {
|
| const long long duration = UnserializeUInt(pReader, pos, size);
|
|
|
| if (duration < 0)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| info.defaultDuration = static_cast<unsigned long long>(duration);
|
| - } else if (id == 0x06) { // CodecID
|
| + } else if (id == mkvmuxer::kMkvCodecID) {
|
| const long status = UnserializeString(pReader, pos, size, info.codecId);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x1C) { // lacing
|
| + } else if (id == mkvmuxer::kMkvFlagLacing) {
|
| lacing = UnserializeUInt(pReader, pos, size);
|
|
|
| if ((lacing < 0) || (lacing > 1))
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x23A2) { // Codec Private
|
| + } else if (id == mkvmuxer::kMkvCodecPrivate) {
|
| delete[] info.codecPrivate;
|
| info.codecPrivate = NULL;
|
| info.codecPrivateSize = 0;
|
| @@ -5390,9 +5509,7 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
|
| const size_t buflen = static_cast<size_t>(size);
|
|
|
| if (buflen) {
|
| - typedef unsigned char* buf_t;
|
| -
|
| - const buf_t buf = new (std::nothrow) unsigned char[buflen];
|
| + unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
|
|
|
| if (buf == NULL)
|
| return -1;
|
| @@ -5407,23 +5524,25 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
|
| info.codecPrivate = buf;
|
| info.codecPrivateSize = buflen;
|
| }
|
| - } else if (id == 0x058688) { // Codec Name
|
| + } else if (id == mkvmuxer::kMkvCodecName) {
|
| const long status =
|
| UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
|
|
|
| if (status)
|
| return status;
|
| - } else if (id == 0x16AA) { // Codec Delay
|
| + } else if (id == mkvmuxer::kMkvCodecDelay) {
|
| info.codecDelay = UnserializeUInt(pReader, pos, size);
|
| - } else if (id == 0x16BB) { // Seek Pre Roll
|
| + } else if (id == mkvmuxer::kMkvSeekPreRoll) {
|
| info.seekPreRoll = UnserializeUInt(pReader, pos, size);
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= track_stop);
|
| + if (pos > track_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == track_stop);
|
| + if (pos != track_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if (info.number <= 0) // not specified
|
| return E_FILE_FORMAT_INVALID;
|
| @@ -5552,97 +5671,87 @@ const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
|
| }
|
|
|
| long Cluster::Load(long long& pos, long& len) const {
|
| - assert(m_pSegment);
|
| - assert(m_pos >= m_element_start);
|
| + if (m_pSegment == NULL)
|
| + return E_PARSE_FAILED;
|
|
|
| if (m_timecode >= 0) // at least partially loaded
|
| return 0;
|
|
|
| - assert(m_pos == m_element_start);
|
| - assert(m_element_size < 0);
|
| + if (m_pos != m_element_start || m_element_size >= 0)
|
| + return E_PARSE_FAILED;
|
|
|
| IMkvReader* const pReader = m_pSegment->m_pReader;
|
| -
|
| long long total, avail;
|
| -
|
| const int status = pReader->Length(&total, &avail);
|
|
|
| if (status < 0) // error
|
| return status;
|
|
|
| - assert((total < 0) || (avail <= total));
|
| - assert((total < 0) || (m_pos <= total)); // TODO: verify this
|
| + if (total >= 0 && (avail > total || m_pos > total))
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| pos = m_pos;
|
|
|
| long long cluster_size = -1;
|
|
|
| - {
|
| - if ((pos + 1) > avail) {
|
| - len = 1;
|
| - return E_BUFFER_NOT_FULL;
|
| - }
|
| -
|
| - long long result = GetUIntLength(pReader, pos, len);
|
| -
|
| - if (result < 0) // error or underflow
|
| - return static_cast<long>(result);
|
| + if ((pos + 1) > avail) {
|
| + len = 1;
|
| + return E_BUFFER_NOT_FULL;
|
| + }
|
|
|
| - if (result > 0) // underflow (weird)
|
| - return E_BUFFER_NOT_FULL;
|
| + long long result = GetUIntLength(pReader, pos, len);
|
|
|
| - // if ((pos + len) > segment_stop)
|
| - // return E_FILE_FORMAT_INVALID;
|
| + if (result < 0) // error or underflow
|
| + return static_cast<long>(result);
|
|
|
| - if ((pos + len) > avail)
|
| - return E_BUFFER_NOT_FULL;
|
| + if (result > 0)
|
| + return E_BUFFER_NOT_FULL;
|
|
|
| - const long long id_ = ReadUInt(pReader, pos, len);
|
| + if ((pos + len) > avail)
|
| + return E_BUFFER_NOT_FULL;
|
|
|
| - if (id_ < 0) // error
|
| - return static_cast<long>(id_);
|
| + const long long id_ = ReadID(pReader, pos, len);
|
|
|
| - if (id_ != 0x0F43B675) // Cluster ID
|
| - return E_FILE_FORMAT_INVALID;
|
| + if (id_ < 0) // error
|
| + return static_cast<long>(id_);
|
|
|
| - pos += len; // consume id
|
| + if (id_ != mkvmuxer::kMkvCluster)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| - // read cluster size
|
| + pos += len; // consume id
|
|
|
| - if ((pos + 1) > avail) {
|
| - len = 1;
|
| - return E_BUFFER_NOT_FULL;
|
| - }
|
| + // read cluster size
|
|
|
| - result = GetUIntLength(pReader, pos, len);
|
| + if ((pos + 1) > avail) {
|
| + len = 1;
|
| + return E_BUFFER_NOT_FULL;
|
| + }
|
|
|
| - if (result < 0) // error
|
| - return static_cast<long>(result);
|
| + result = GetUIntLength(pReader, pos, len);
|
|
|
| - if (result > 0) // weird
|
| - return E_BUFFER_NOT_FULL;
|
| + if (result < 0) // error
|
| + return static_cast<long>(result);
|
|
|
| - // if ((pos + len) > segment_stop)
|
| - // return E_FILE_FORMAT_INVALID;
|
| + if (result > 0)
|
| + return E_BUFFER_NOT_FULL;
|
|
|
| - if ((pos + len) > avail)
|
| - return E_BUFFER_NOT_FULL;
|
| + if ((pos + len) > avail)
|
| + return E_BUFFER_NOT_FULL;
|
|
|
| - const long long size = ReadUInt(pReader, pos, len);
|
| + const long long size = ReadUInt(pReader, pos, len);
|
|
|
| - if (size < 0) // error
|
| - return static_cast<long>(cluster_size);
|
| + if (size < 0) // error
|
| + return static_cast<long>(cluster_size);
|
|
|
| - if (size == 0)
|
| - return E_FILE_FORMAT_INVALID; // TODO: verify this
|
| + if (size == 0)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| - pos += len; // consume length of size of element
|
| + pos += len; // consume length of size of element
|
|
|
| - const long long unknown_size = (1LL << (7 * len)) - 1;
|
| + const long long unknown_size = (1LL << (7 * len)) - 1;
|
|
|
| - if (size != unknown_size)
|
| - cluster_size = size;
|
| - }
|
| + if (size != unknown_size)
|
| + cluster_size = size;
|
|
|
| // pos points to start of payload
|
| long long timecode = -1;
|
| @@ -5667,7 +5776,7 @@ long Cluster::Load(long long& pos, long& len) const {
|
| if (result < 0) // error
|
| return static_cast<long>(result);
|
|
|
| - if (result > 0) // weird
|
| + if (result > 0)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
|
| @@ -5676,7 +5785,7 @@ long Cluster::Load(long long& pos, long& len) const {
|
| if ((pos + len) > avail)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| + const long long id = ReadID(pReader, pos, len);
|
|
|
| if (id < 0) // error
|
| return static_cast<long>(id);
|
| @@ -5688,10 +5797,10 @@ long Cluster::Load(long long& pos, long& len) const {
|
| // that we have exhausted the sub-element's inside the cluster
|
| // whose ID we parsed earlier.
|
|
|
| - if (id == 0x0F43B675) // Cluster ID
|
| + if (id == mkvmuxer::kMkvCluster)
|
| break;
|
|
|
| - if (id == 0x0C53BB6B) // Cues ID
|
| + if (id == mkvmuxer::kMkvCues)
|
| break;
|
|
|
| pos += len; // consume ID field
|
| @@ -5708,7 +5817,7 @@ long Cluster::Load(long long& pos, long& len) const {
|
| if (result < 0) // error
|
| return static_cast<long>(result);
|
|
|
| - if (result > 0) // weird
|
| + if (result > 0)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
|
| @@ -5734,13 +5843,13 @@ long Cluster::Load(long long& pos, long& len) const {
|
|
|
| // pos now points to start of payload
|
|
|
| - if (size == 0) // weird
|
| + if (size == 0)
|
| continue;
|
|
|
| if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| - if (id == 0x67) { // TimeCode ID
|
| + if (id == mkvmuxer::kMkvTimecode) {
|
| len = static_cast<long>(size);
|
|
|
| if ((pos + size) > avail)
|
| @@ -5755,19 +5864,21 @@ long Cluster::Load(long long& pos, long& len) const {
|
|
|
| if (bBlock)
|
| break;
|
| - } else if (id == 0x20) { // BlockGroup ID
|
| + } else if (id == mkvmuxer::kMkvBlockGroup) {
|
| bBlock = true;
|
| break;
|
| - } else if (id == 0x23) { // SimpleBlock ID
|
| + } else if (id == mkvmuxer::kMkvSimpleBlock) {
|
| bBlock = true;
|
| break;
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert((cluster_stop < 0) || (pos <= cluster_stop));
|
| + if (cluster_stop >= 0 && pos > cluster_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert((cluster_stop < 0) || (pos <= cluster_stop));
|
| + if (cluster_stop >= 0 && pos > cluster_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if (timecode < 0) // no timecode found
|
| return E_FILE_FORMAT_INVALID;
|
| @@ -5790,10 +5901,8 @@ long Cluster::Parse(long long& pos, long& len) const {
|
| if (status < 0)
|
| return status;
|
|
|
| - assert(m_pos >= m_element_start);
|
| - assert(m_timecode >= 0);
|
| - // assert(m_size > 0);
|
| - // assert(m_element_size > m_size);
|
| + if (m_pos < m_element_start || m_timecode < 0)
|
| + return E_PARSE_FAILED;
|
|
|
| const long long cluster_stop =
|
| (m_element_size < 0) ? -1 : m_element_start + m_element_size;
|
| @@ -5810,7 +5919,8 @@ long Cluster::Parse(long long& pos, long& len) const {
|
| if (status < 0) // error
|
| return status;
|
|
|
| - assert((total < 0) || (avail <= total));
|
| + if (total >= 0 && avail > total)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| pos = m_pos;
|
|
|
| @@ -5837,7 +5947,7 @@ long Cluster::Parse(long long& pos, long& len) const {
|
| if (result < 0) // error
|
| return static_cast<long>(result);
|
|
|
| - if (result > 0) // weird
|
| + if (result > 0)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
|
| @@ -5846,19 +5956,16 @@ long Cluster::Parse(long long& pos, long& len) const {
|
| if ((pos + len) > avail)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| -
|
| - if (id < 0) // error
|
| - return static_cast<long>(id);
|
| + const long long id = ReadID(pReader, pos, len);
|
|
|
| - if (id == 0) // weird
|
| + if (id < 0)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| // This is the distinguished set of ID's we use to determine
|
| // that we have exhausted the sub-element's inside the cluster
|
| // whose ID we parsed earlier.
|
|
|
| - if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { // Cluster or Cues ID
|
| + if ((id == mkvmuxer::kMkvCluster) || (id == mkvmuxer::kMkvCues)) {
|
| if (m_element_size < 0)
|
| m_element_size = pos - m_element_start;
|
|
|
| @@ -5879,7 +5986,7 @@ long Cluster::Parse(long long& pos, long& len) const {
|
| if (result < 0) // error
|
| return static_cast<long>(result);
|
|
|
| - if (result > 0) // weird
|
| + if (result > 0)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
|
| @@ -5905,7 +6012,7 @@ long Cluster::Parse(long long& pos, long& len) const {
|
|
|
| // pos now points to start of payload
|
|
|
| - if (size == 0) // weird
|
| + if (size == 0)
|
| continue;
|
|
|
| // const long long block_start = pos;
|
| @@ -5913,8 +6020,10 @@ long Cluster::Parse(long long& pos, long& len) const {
|
|
|
| if (cluster_stop >= 0) {
|
| if (block_stop > cluster_stop) {
|
| - if ((id == 0x20) || (id == 0x23))
|
| + if (id == mkvmuxer::kMkvBlockGroup ||
|
| + id == mkvmuxer::kMkvSimpleBlock) {
|
| return E_FILE_FORMAT_INVALID;
|
| + }
|
|
|
| pos = cluster_stop;
|
| break;
|
| @@ -5930,42 +6039,48 @@ long Cluster::Parse(long long& pos, long& len) const {
|
|
|
| Cluster* const this_ = const_cast<Cluster*>(this);
|
|
|
| - if (id == 0x20) // BlockGroup
|
| + if (id == mkvmuxer::kMkvBlockGroup)
|
| return this_->ParseBlockGroup(size, pos, len);
|
|
|
| - if (id == 0x23) // SimpleBlock
|
| + if (id == mkvmuxer::kMkvSimpleBlock)
|
| return this_->ParseSimpleBlock(size, pos, len);
|
|
|
| pos += size; // consume payload
|
| - assert((cluster_stop < 0) || (pos <= cluster_stop));
|
| + if (cluster_stop >= 0 && pos > cluster_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(m_element_size > 0);
|
| + if (m_element_size < 1)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| m_pos = pos;
|
| - assert((cluster_stop < 0) || (m_pos <= cluster_stop));
|
| + if (cluster_stop >= 0 && m_pos > cluster_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if (m_entries_count > 0) {
|
| const long idx = m_entries_count - 1;
|
|
|
| const BlockEntry* const pLast = m_entries[idx];
|
| - assert(pLast);
|
| + if (pLast == NULL)
|
| + return E_PARSE_FAILED;
|
|
|
| const Block* const pBlock = pLast->GetBlock();
|
| - assert(pBlock);
|
| + if (pBlock == NULL)
|
| + return E_PARSE_FAILED;
|
|
|
| const long long start = pBlock->m_start;
|
|
|
| if ((total >= 0) && (start > total))
|
| - return -1; // defend against trucated stream
|
| + return E_PARSE_FAILED; // defend against trucated stream
|
|
|
| const long long size = pBlock->m_size;
|
|
|
| const long long stop = start + size;
|
| - assert((cluster_stop < 0) || (stop <= cluster_stop));
|
| + if (cluster_stop >= 0 && stop > cluster_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if ((total >= 0) && (stop > total))
|
| - return -1; // defend against trucated stream
|
| + return E_PARSE_FAILED; // defend against trucated stream
|
| }
|
|
|
| return 1; // no more entries
|
| @@ -6058,7 +6173,7 @@ long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
|
| return E_BUFFER_NOT_FULL;
|
| }
|
|
|
| - status = CreateBlock(0x23, // simple block id
|
| + status = CreateBlock(mkvmuxer::kMkvSimpleBlock,
|
| block_start, block_size,
|
| 0); // DiscardPadding
|
|
|
| @@ -6118,12 +6233,12 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
|
| if ((pos + len) > avail)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| + const long long id = ReadID(pReader, pos, len);
|
|
|
| if (id < 0) // error
|
| return static_cast<long>(id);
|
|
|
| - if (id == 0) // not a value ID
|
| + if (id == 0) // not a valid ID
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| pos += len; // consume ID field
|
| @@ -6169,14 +6284,14 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
|
| if (size == unknown_size)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| - if (id == 0x35A2) { // DiscardPadding
|
| + if (id == mkvmuxer::kMkvDiscardPadding) {
|
| status = UnserializeInt(pReader, pos, size, discard_padding);
|
|
|
| if (status < 0) // error
|
| return status;
|
| }
|
|
|
| - if (id != 0x21) { // sub-part of BlockGroup is not a Block
|
| + if (id != mkvmuxer::kMkvBlock) {
|
| pos += size; // consume sub-part of block group
|
|
|
| if (pos > payload_stop)
|
| @@ -6262,12 +6377,14 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
|
| }
|
|
|
| pos = block_stop; // consume block-part of block group
|
| - assert(pos <= payload_stop);
|
| + if (pos > payload_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
|
|
| - assert(pos == payload_stop);
|
| + if (pos != payload_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| - status = CreateBlock(0x20, // BlockGroup ID
|
| + status = CreateBlock(mkvmuxer::kMkvBlockGroup,
|
| payload_start, payload_size, discard_padding);
|
| if (status != 0)
|
| return status;
|
| @@ -6310,17 +6427,14 @@ long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
|
| return E_BUFFER_NOT_FULL; // underflow, since more remains to be parsed
|
| }
|
|
|
| -Cluster* Cluster::Create(Segment* pSegment, long idx, long long off)
|
| -// long long element_size)
|
| -{
|
| - assert(pSegment);
|
| - assert(off >= 0);
|
| +Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
|
| + if (!pSegment || off < 0)
|
| + return NULL;
|
|
|
| const long long element_start = pSegment->m_start + off;
|
|
|
| - Cluster* const pCluster = new Cluster(pSegment, idx, element_start);
|
| - // element_size);
|
| - assert(pCluster);
|
| + Cluster* const pCluster =
|
| + new (std::nothrow) Cluster(pSegment, idx, element_start);
|
|
|
| return pCluster;
|
| }
|
| @@ -6431,13 +6545,13 @@ long Cluster::HasBlockEntries(
|
| if ((pos + len) > avail)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| + const long long id = ReadID(pReader, pos, len);
|
|
|
| if (id < 0) // error
|
| return static_cast<long>(id);
|
|
|
| - if (id != 0x0F43B675) // weird: not cluster ID
|
| - return -1; // generic error
|
| + if (id != mkvmuxer::kMkvCluster)
|
| + return E_PARSE_FAILED;
|
|
|
| pos += len; // consume Cluster ID field
|
|
|
| @@ -6515,7 +6629,7 @@ long Cluster::HasBlockEntries(
|
| if ((pos + len) > avail)
|
| return E_BUFFER_NOT_FULL;
|
|
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| + const long long id = ReadID(pReader, pos, len);
|
|
|
| if (id < 0) // error
|
| return static_cast<long>(id);
|
| @@ -6524,10 +6638,10 @@ long Cluster::HasBlockEntries(
|
| // that we have exhausted the sub-element's inside the cluster
|
| // whose ID we parsed earlier.
|
|
|
| - if (id == 0x0F43B675) // Cluster ID
|
| + if (id == mkvmuxer::kMkvCluster)
|
| return 0; // no entries found
|
|
|
| - if (id == 0x0C53BB6B) // Cues ID
|
| + if (id == mkvmuxer::kMkvCues)
|
| return 0; // no entries found
|
|
|
| pos += len; // consume id field
|
| @@ -6579,14 +6693,15 @@ long Cluster::HasBlockEntries(
|
| if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| - if (id == 0x20) // BlockGroup ID
|
| + if (id == mkvmuxer::kMkvBlockGroup)
|
| return 1; // have at least one entry
|
|
|
| - if (id == 0x23) // SimpleBlock ID
|
| + if (id == mkvmuxer::kMkvSimpleBlock)
|
| return 1; // have at least one entry
|
|
|
| pos += size; // consume payload
|
| - assert((cluster_stop < 0) || (pos <= cluster_stop));
|
| + if (cluster_stop >= 0 && pos > cluster_stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
| }
|
|
|
| @@ -6656,14 +6771,17 @@ long long Cluster::GetLastTime() const {
|
| long Cluster::CreateBlock(long long id,
|
| long long pos, // absolute pos of payload
|
| long long size, long long discard_padding) {
|
| - assert((id == 0x20) || (id == 0x23)); // BlockGroup or SimpleBlock
|
| + if (id != mkvmuxer::kMkvBlockGroup && id != mkvmuxer::kMkvSimpleBlock)
|
| + return E_PARSE_FAILED;
|
|
|
| if (m_entries_count < 0) { // haven't parsed anything yet
|
| assert(m_entries == NULL);
|
| assert(m_entries_size == 0);
|
|
|
| m_entries_size = 1024;
|
| - m_entries = new BlockEntry*[m_entries_size];
|
| + m_entries = new (std::nothrow) BlockEntry*[m_entries_size];
|
| + if (m_entries == NULL)
|
| + return -1;
|
|
|
| m_entries_count = 0;
|
| } else {
|
| @@ -6674,8 +6792,9 @@ long Cluster::CreateBlock(long long id,
|
| if (m_entries_count >= m_entries_size) {
|
| const long entries_size = 2 * m_entries_size;
|
|
|
| - BlockEntry** const entries = new BlockEntry*[entries_size];
|
| - assert(entries);
|
| + BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
|
| + if (entries == NULL)
|
| + return -1;
|
|
|
| BlockEntry** src = m_entries;
|
| BlockEntry** const src_end = src + m_entries_count;
|
| @@ -6692,9 +6811,9 @@ long Cluster::CreateBlock(long long id,
|
| }
|
| }
|
|
|
| - if (id == 0x20) // BlockGroup ID
|
| + if (id == mkvmuxer::kMkvBlockGroup)
|
| return CreateBlockGroup(pos, size, discard_padding);
|
| - else // SimpleBlock ID
|
| + else
|
| return CreateSimpleBlock(pos, size);
|
| }
|
|
|
| @@ -6725,9 +6844,9 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
|
|
|
| while (pos < stop) {
|
| long len;
|
| - const long long id = ReadUInt(pReader, pos, len);
|
| - assert(id >= 0); // TODO
|
| - assert((pos + len) <= stop);
|
| + const long long id = ReadID(pReader, pos, len);
|
| + if (id < 0 || (pos + len) > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| pos += len; // consume ID
|
|
|
| @@ -6737,12 +6856,12 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
|
|
|
| pos += len; // consume size
|
|
|
| - if (id == 0x21) { // Block ID
|
| + if (id == mkvmuxer::kMkvBlock) {
|
| if (bpos < 0) { // Block ID
|
| bpos = pos;
|
| bsize = size;
|
| }
|
| - } else if (id == 0x1B) { // Duration ID
|
| + } else if (id == mkvmuxer::kMkvBlockDuration) {
|
| if (size > 8)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| @@ -6750,7 +6869,7 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
|
|
|
| if (duration < 0)
|
| return E_FILE_FORMAT_INVALID;
|
| - } else if (id == 0x7B) { // ReferenceBlock
|
| + } else if (id == mkvmuxer::kMkvReferenceBlock) {
|
| if (size > 8 || size <= 0)
|
| return E_FILE_FORMAT_INVALID;
|
| const long size_ = static_cast<long>(size);
|
| @@ -6764,17 +6883,19 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
|
|
|
| if (time <= 0) // see note above
|
| prev = time;
|
| - else // weird
|
| + else
|
| next = time;
|
| }
|
|
|
| pos += size; // consume payload
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| }
|
| if (bpos < 0)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| - assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| assert(bsize >= 0);
|
|
|
| const long idx = m_entries_count;
|
| @@ -7213,7 +7334,9 @@ long Block::Parse(const Cluster* pCluster) {
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| m_frame_count = 1;
|
| - m_frames = new Frame[m_frame_count];
|
| + m_frames = new (std::nothrow) Frame[m_frame_count];
|
| + if (m_frames == NULL)
|
| + return -1;
|
|
|
| Frame& f = m_frames[0];
|
| f.pos = pos;
|
| @@ -7239,18 +7362,23 @@ long Block::Parse(const Cluster* pCluster) {
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| ++pos; // consume frame count
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| m_frame_count = int(biased_count) + 1;
|
|
|
| - m_frames = new Frame[m_frame_count];
|
| - assert(m_frames);
|
| + m_frames = new (std::nothrow) Frame[m_frame_count];
|
| + if (m_frames == NULL)
|
| + return -1;
|
| +
|
| + if (!m_frames)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| if (lacing == 1) { // Xiph
|
| Frame* pf = m_frames;
|
| Frame* const pf_end = pf + m_frame_count;
|
|
|
| - long size = 0;
|
| + long long size = 0;
|
| int frame_count = m_frame_count;
|
|
|
| while (frame_count > 1) {
|
| @@ -7277,6 +7405,8 @@ long Block::Parse(const Cluster* pCluster) {
|
|
|
| Frame& f = *pf++;
|
| assert(pf < pf_end);
|
| + if (pf >= pf_end)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| f.pos = 0; // patch later
|
|
|
| @@ -7289,8 +7419,8 @@ long Block::Parse(const Cluster* pCluster) {
|
| --frame_count;
|
| }
|
|
|
| - assert(pf < pf_end);
|
| - assert(pos <= stop);
|
| + if (pf >= pf_end || pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| {
|
| Frame& f = *pf++;
|
| @@ -7318,11 +7448,17 @@ long Block::Parse(const Cluster* pCluster) {
|
| Frame& f = *pf++;
|
| assert((pos + f.len) <= stop);
|
|
|
| + if ((pos + f.len) > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| f.pos = pos;
|
| pos += f.len;
|
| }
|
|
|
| assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| } else if (lacing == 2) { // fixed-size lacing
|
| if (pos >= stop)
|
| return E_FILE_FORMAT_INVALID;
|
| @@ -7342,6 +7478,8 @@ long Block::Parse(const Cluster* pCluster) {
|
|
|
| while (pf != pf_end) {
|
| assert((pos + frame_size) <= stop);
|
| + if ((pos + frame_size) > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| Frame& f = *pf++;
|
|
|
| @@ -7352,13 +7490,16 @@ long Block::Parse(const Cluster* pCluster) {
|
| }
|
|
|
| assert(pos == stop);
|
| + if (pos != stop)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
| } else {
|
| assert(lacing == 3); // EBML lacing
|
|
|
| if (pos >= stop)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| - long size = 0;
|
| + long long size = 0;
|
| int frame_count = m_frame_count;
|
|
|
| long long frame_size = ReadUInt(pReader, pos, len);
|
| @@ -7396,6 +7537,9 @@ long Block::Parse(const Cluster* pCluster) {
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| assert(pf < pf_end);
|
| + if (pf >= pf_end)
|
| + return E_FILE_FORMAT_INVALID;
|
| +
|
|
|
| const Frame& prev = *pf++;
|
| assert(prev.len == frame_size);
|
| @@ -7403,6 +7547,8 @@ long Block::Parse(const Cluster* pCluster) {
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| assert(pf < pf_end);
|
| + if (pf >= pf_end)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| Frame& curr = *pf;
|
|
|
| @@ -7417,7 +7563,8 @@ long Block::Parse(const Cluster* pCluster) {
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| pos += len; // consume length of (delta) size
|
| - assert(pos <= stop);
|
| + if (pos > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| const int exp = 7 * len - 1;
|
| const long long bias = (1LL << exp) - 1LL;
|
| @@ -7439,18 +7586,20 @@ long Block::Parse(const Cluster* pCluster) {
|
|
|
| // parse last frame
|
| if (frame_count > 0) {
|
| - assert(pos <= stop);
|
| - assert(pf < pf_end);
|
| + if (pos > stop || pf >= pf_end)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| const Frame& prev = *pf++;
|
| assert(prev.len == frame_size);
|
| if (prev.len != frame_size)
|
| return E_FILE_FORMAT_INVALID;
|
|
|
| - assert(pf < pf_end);
|
| + if (pf >= pf_end)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| Frame& curr = *pf++;
|
| - assert(pf == pf_end);
|
| + if (pf != pf_end)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| curr.pos = 0; // patch later
|
|
|
| @@ -7471,6 +7620,8 @@ long Block::Parse(const Cluster* pCluster) {
|
| while (pf != pf_end) {
|
| Frame& f = *pf++;
|
| assert((pos + f.len) <= stop);
|
| + if ((pos + f.len) > stop)
|
| + return E_FILE_FORMAT_INVALID;
|
|
|
| f.pos = pos;
|
| pos += f.len;
|
|
|