7724 lines · 177.5 KB · C++
RawDownload
// 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t