// Copyright (c) 2012 The WebM project authors. All Rights Reserved.//// Use of this source code is governed by a BSD-style license// that can be found in the LICENSE file in the root of the source// tree. An additional intellectual property rights grant can be found// in the file PATENTS. All contributing project authors may// be found in the AUTHORS file in the root of the source tree. #include "mkvparser.hpp" #if defined(_MSC_VER) && _MSC_VER < 1800#include <float.h> // _isnan() / _finite()#define MSC_COMPAT#endif #include <cassert>#include <climits>#include <cmath>#include <cstring>#include <new> #include "webmids.hpp" #ifdef _MSC_VER// Disable MSVC warnings that suggest making code non-portable.#pragma warning(disable : 4996)#endif namespace mkvparser { #ifdef MSC_COMPATinline bool isnan(double val) { return !!_isnan(val); }inline bool isinf(double val) { return !_finite(val); }#elseinline bool isnan(double val) { return std::isnan(val); }inline bool isinf(double val) { return std::isinf(val); }#endif // MSC_COMPAT 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; if (num_bytes != static_cast<size_t>(num_bytes)) return NULL; return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];} void GetVersion(int& major, int& minor, int& build, int& revision) { major = 1; minor = 0; build = 0; revision = 30;} long long ReadUInt(IMkvReader* pReader, long long pos, long& len) { if (!pReader || pos < 0) return E_FILE_FORMAT_INVALID; len = 1; unsigned char b; int status = pReader->Read(pos, 1, &b); if (status < 0) // error or underflow return status; if (status > 0) // interpreted as "underflow" return E_BUFFER_NOT_FULL; if (b == 0) // we can't handle u-int values larger than 8 bytes return E_FILE_FORMAT_INVALID; unsigned char m = 0x80; while (!(b & m)) { m >>= 1; ++len; } long long result = b & (~m); ++pos; for (int i = 1; i < len; ++i) { status = pReader->Read(pos, 1, &b); if (status < 0) { len = 1; return status; } if (status > 0) { len = 1; return E_BUFFER_NOT_FULL; } result <<= 8; result |= b; ++pos; } return result;} // 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); if (status < 0 || (total >= 0 && available > total)) return E_FILE_FORMAT_INVALID; len = 1; if (pos >= available) return pos; // too few bytes available unsigned char b; status = pReader->Read(pos, 1, &b); if (status != 0) return status; if (b == 0) // we can't handle u-int values larger than 8 bytes return E_FILE_FORMAT_INVALID; unsigned char m = 0x80; while (!(b & m)) { m >>= 1; ++len; } return 0; // success} // TODO(vigneshv): This function assumes that unsigned values never have their// high bit set.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; for (long long i = 0; i < size; ++i) { unsigned char b; const long status = pReader->Read(pos, 1, &b); if (status < 0) return status; result <<= 8; result |= b; ++pos; } return result;} 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_); unsigned char buf[8]; const int status = pReader->Read(pos, size, buf); if (status < 0) // error return status; if (size == 4) { union { float f; unsigned long ff; }; ff = 0; for (int i = 0;;) { ff |= buf[i]; if (++i >= 4) break; ff <<= 8; } result = f; } else { union { double d; unsigned long long dd; }; dd = 0; for (int i = 0;;) { dd |= buf[i]; if (++i >= 8) break; dd <<= 8; } result = d; } if (mkvparser::isinf(result) || mkvparser::isnan(result)) return E_FILE_FORMAT_INVALID; return 0;} 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; signed char first_byte = 0; const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte); if (status < 0) return status; unsigned long long result = first_byte; ++pos; for (long i = 1; i < size; ++i) { unsigned char b; const long status = pReader->Read(pos, 1, &b); if (status < 0) return status; result <<= 8; result |= b; ++pos; } result_ref = static_cast<long long>(result); return 0;} long UnserializeString(IMkvReader* pReader, long long pos, long long size, char*& str) { delete[] str; str = NULL; if (size >= LONG_MAX || size < 0) return E_FILE_FORMAT_INVALID; // +1 for '\0' terminator const long required_size = static_cast<long>(size) + 1; str = SafeArrayAlloc<char>(1, required_size); if (str == NULL) return E_FILE_FORMAT_INVALID; unsigned char* const buf = reinterpret_cast<unsigned char*>(str); const long status = pReader->Read(pos, static_cast<long>(size), buf); if (status) { delete[] str; str = NULL; return status; } str[required_size - 1] = '\0'; return 0;} 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 = ReadID(pReader, pos, len); if (id < 0) return E_FILE_FORMAT_INVALID; pos += len; // consume id if (stop >= 0 && pos >= stop) return E_FILE_FORMAT_INVALID; size = ReadUInt(pReader, pos, len); 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 LLONG_MAX. const unsigned long long rollover_check = static_cast<unsigned long long>(pos) + len; if (rollover_check > LLONG_MAX) return E_FILE_FORMAT_INVALID; pos += len; // consume length of size // pos now designates payload if (stop >= 0 && pos >= stop) return E_FILE_FORMAT_INVALID; return 0; // success} bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id, long long& val) { if (!pReader || pos < 0) return false; long long total = 0; long long available = 0; const long status = pReader->Length(&total, &available); if (status < 0 || (total >= 0 && available > total)) return false; long len = 0; const long long id = ReadID(pReader, pos, len); if (id < 0 || (available - pos) > len) return false; if (static_cast<unsigned long>(id) != expected_id) return false; pos += len; // consume id const long long size = ReadUInt(pReader, pos, len); 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); if (val < 0) return false; pos += size; // consume size of payload return true;} 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 = 0; long long available = 0; long status = pReader->Length(&total, &available); if (status < 0 || (total >= 0 && available > total)) return false; long len = 0; const long long id = ReadID(pReader, pos, len); if (id < 0 || (available - pos) > len) return false; if (static_cast<unsigned long>(id) != expected_id) return false; pos += len; // consume id 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 > LLONG_MAX) return false; pos += len; // consume length of size of payload rollover_check = static_cast<unsigned long long>(pos) + size; if (rollover_check > LLONG_MAX) return false; 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); if (status != 0) return false; buflen = buflen_; pos += size; // consume size of payload return true;} EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); } EBMLHeader::~EBMLHeader() { delete[] m_docType; } void EBMLHeader::Init() { m_version = 1; m_readVersion = 1; m_maxIdLength = 4; m_maxSizeLength = 8;Lines 1–500 of 7724. Load more
// Copyright (c) 2012 The WebM project authors. All Rights Reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file in the root of the source // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. #include "mkvparser.hpp" #if defined(_MSC_VER) && _MSC_VER < 1800 #include <float.h> // _isnan() / _finite() #define MSC_COMPAT #endif #include <cassert> #include <climits> #include <cmath> #include <cstring> #include <new> #include "webmids.hpp" #ifdef _MSC_VER // Disable MSVC warnings that suggest making code non-portable. #pragma warning(disable : 4996) #endif namespace mkvparser { #ifdef MSC_COMPAT inline bool isnan(double val) { return !!_isnan(val); } inline bool isinf(double val) { return !_finite(val); } #else inline bool isnan(double val) { return std::isnan(val); } inline bool isinf(double val) { return std::isinf(val); } #endif // MSC_COMPAT 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; if (num_bytes != static_cast<size_t>(num_bytes)) return NULL; return new (std::nothrow) Type[static_cast<size_t>(num_bytes)]; } void GetVersion(int& major, int& minor, int& build, int& revision) { major = 1; minor = 0; build = 0; revision = 30; } long long ReadUInt(IMkvReader* pReader, long long pos, long& len) { if (!pReader || pos < 0) return E_FILE_FORMAT_INVALID; len = 1; unsigned char b; int status = pReader->Read(pos, 1, &b); if (status < 0) // error or underflow return status; if (status > 0) // interpreted as "underflow" return E_BUFFER_NOT_FULL; if (b == 0) // we can't handle u-int values larger than 8 bytes return E_FILE_FORMAT_INVALID; unsigned char m = 0x80; while (!(b & m)) { m >>= 1; ++len; } long long result = b & (~m); ++pos; for (int i = 1; i < len; ++i) { status = pReader->Read(pos, 1, &b); if (status < 0) { len = 1; return status; } if (status > 0) { len = 1; return E_BUFFER_NOT_FULL; } result <<= 8; result |= b; ++pos; } return result; } // 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); if (status < 0 || (total >= 0 && available > total)) return E_FILE_FORMAT_INVALID; len = 1; if (pos >= available) return pos; // too few bytes available unsigned char b; status = pReader->Read(pos, 1, &b); if (status != 0) return status; if (b == 0) // we can't handle u-int values larger than 8 bytes return E_FILE_FORMAT_INVALID; unsigned char m = 0x80; while (!(b & m)) { m >>= 1; ++len; } return 0; // success } // TODO(vigneshv): This function assumes that unsigned values never have their // high bit set. 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; for (long long i = 0; i < size; ++i) { unsigned char b; const long status = pReader->Read(pos, 1, &b); if (status < 0) return status; result <<= 8; result |= b; ++pos; } return result; } 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_); unsigned char buf[8]; const int status = pReader->Read(pos, size, buf); if (status < 0) // error return status; if (size == 4) { union { float f; unsigned long ff; }; ff = 0; for (int i = 0;;) { ff |= buf[i]; if (++i >= 4) break; ff <<= 8; } result = f; } else { union { double d; unsigned long long dd; }; dd = 0; for (int i = 0;;) { dd |= buf[i]; if (++i >= 8) break; dd <<= 8; } result = d; } if (mkvparser::isinf(result) || mkvparser::isnan(result)) return E_FILE_FORMAT_INVALID; return 0; } 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; signed char first_byte = 0; const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte); if (status < 0) return status; unsigned long long result = first_byte; ++pos; for (long i = 1; i < size; ++i) { unsigned char b; const long status = pReader->Read(pos, 1, &b); if (status < 0) return status; result <<= 8; result |= b; ++pos; } result_ref = static_cast<long long>(result); return 0; } long UnserializeString(IMkvReader* pReader, long long pos, long long size, char*& str) { delete[] str; str = NULL; if (size >= LONG_MAX || size < 0) return E_FILE_FORMAT_INVALID; // +1 for '\0' terminator const long required_size = static_cast<long>(size) + 1; str = SafeArrayAlloc<char>(1, required_size); if (str == NULL) return E_FILE_FORMAT_INVALID; unsigned char* const buf = reinterpret_cast<unsigned char*>(str); const long status = pReader->Read(pos, static_cast<long>(size), buf); if (status) { delete[] str; str = NULL; return status; } str[required_size - 1] = '\0'; return 0; } 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 = ReadID(pReader, pos, len); if (id < 0) return E_FILE_FORMAT_INVALID; pos += len; // consume id if (stop >= 0 && pos >= stop) return E_FILE_FORMAT_INVALID; size = ReadUInt(pReader, pos, len); 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 LLONG_MAX. const unsigned long long rollover_check = static_cast<unsigned long long>(pos) + len; if (rollover_check > LLONG_MAX) return E_FILE_FORMAT_INVALID; pos += len; // consume length of size // pos now designates payload if (stop >= 0 && pos >= stop) return E_FILE_FORMAT_INVALID; return 0; // success } bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id, long long& val) { if (!pReader || pos < 0) return false; long long total = 0; long long available = 0; const long status = pReader->Length(&total, &available); if (status < 0 || (total >= 0 && available > total)) return false; long len = 0; const long long id = ReadID(pReader, pos, len); if (id < 0 || (available - pos) > len) return false; if (static_cast<unsigned long>(id) != expected_id) return false; pos += len; // consume id const long long size = ReadUInt(pReader, pos, len); 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); if (val < 0) return false; pos += size; // consume size of payload return true; } 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 = 0; long long available = 0; long status = pReader->Length(&total, &available); if (status < 0 || (total >= 0 && available > total)) return false; long len = 0; const long long id = ReadID(pReader, pos, len); if (id < 0 || (available - pos) > len) return false; if (static_cast<unsigned long>(id) != expected_id) return false; pos += len; // consume id 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 > LLONG_MAX) return false; pos += len; // consume length of size of payload rollover_check = static_cast<unsigned long long>(pos) + size; if (rollover_check > LLONG_MAX) return false; 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); if (status != 0) return false; buflen = buflen_; pos += size; // consume size of payload return true; } EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); } EBMLHeader::~EBMLHeader() { delete[] m_docType; } void EBMLHeader::Init() { m_version = 1; m_readVersion = 1; m_maxIdLength = 4; m_maxSizeLength = 8;