Update libwebm

Update of libwebm.

Up-to-date version of libwebm contains several bugfixes that allow playback of files that would crash Godot otherwise.
This commit is contained in:
ShyRed 2018-03-09 17:28:08 +01:00
parent b842369442
commit e71f109910
5 changed files with 372 additions and 110 deletions

View file

@ -18,6 +18,10 @@ thirdparty_libsimplewebm_sources = [thirdparty_libsimplewebm_dir + file for file
env_webm.add_source_files(env.modules_sources, thirdparty_libsimplewebm_sources) env_webm.add_source_files(env.modules_sources, thirdparty_libsimplewebm_sources)
env_webm.Append(CPPPATH=[thirdparty_libsimplewebm_dir, thirdparty_libsimplewebm_dir + "libwebm/"]) env_webm.Append(CPPPATH=[thirdparty_libsimplewebm_dir, thirdparty_libsimplewebm_dir + "libwebm/"])
# upstream uses c++11
if (not env_webm.msvc):
env_webm.Append(CCFLAGS="-std=c++11")
# also requires libogg, libvorbis and libopus # also requires libogg, libvorbis and libopus
if env['builtin_libogg']: if env['builtin_libogg']:
env_webm.Append(CPPPATH=["#thirdparty/libogg"]) env_webm.Append(CPPPATH=["#thirdparty/libogg"])

View file

@ -1,5 +1,5 @@
URL: https://chromium.googlesource.com/webm/libwebm URL: https://chromium.googlesource.com/webm/libwebm
Version: 32d5ac49414a8914ec1e1f285f3f927c6e8ec29d Version: d7c62173ff6b4a5e0a2f86683a5b67db98cf09bf
License: BSD License: BSD
License File: LICENSE.txt License File: LICENSE.txt

View file

@ -124,6 +124,14 @@ enum MkvId {
kMkvLuminanceMin = 0x55DA, kMkvLuminanceMin = 0x55DA,
// end mastering metadata // end mastering metadata
// end colour // end colour
// projection
kMkvProjection = 0x7670,
kMkvProjectionType = 0x7671,
kMkvProjectionPrivate = 0x7672,
kMkvProjectionPoseYaw = 0x7673,
kMkvProjectionPosePitch = 0x7674,
kMkvProjectionPoseRoll = 0x7675,
// end projection
// audio // audio
kMkvAudio = 0xE1, kMkvAudio = 0xE1,
kMkvSamplingFrequency = 0xB5, kMkvSamplingFrequency = 0xB5,

View file

@ -12,51 +12,30 @@
#define MSC_COMPAT #define MSC_COMPAT
#endif #endif
#include <assert.h> #include <cassert>
#include <float.h> #include <cfloat>
#include <limits.h> #include <climits>
#include <math.h> #include <cmath>
#include <string.h> #include <cstring>
#include <memory>
#include <new>
#include "common/webmids.h" #include "common/webmids.h"
namespace mkvparser { namespace mkvparser {
const long long kStringElementSizeLimit = 20 * 1000 * 1000;
const float MasteringMetadata::kValueNotPresent = FLT_MAX; const float MasteringMetadata::kValueNotPresent = FLT_MAX;
const long long Colour::kValueNotPresent = LLONG_MAX; const long long Colour::kValueNotPresent = LLONG_MAX;
const float Projection::kValueNotPresent = FLT_MAX;
#ifdef MSC_COMPAT #ifdef MSC_COMPAT
inline bool isnan(double val) { return !!_isnan(val); } inline bool isnan(double val) { return !!_isnan(val); }
inline bool isinf(double val) { return !_finite(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 #endif // MSC_COMPAT
template<typename T>
class my_auto_ptr {
my_auto_ptr(const my_auto_ptr &);
T *operator =(const my_auto_ptr &);
T *m_ptr;
public:
my_auto_ptr(T *ptr) :
m_ptr(ptr)
{}
my_auto_ptr() :
m_ptr(NULL)
{}
~my_auto_ptr() {
delete m_ptr;
}
T *release() {
T *ptr = m_ptr;
m_ptr = NULL;
return ptr;
}
T *operator ->() const {
return m_ptr;
}
};
IMkvReader::~IMkvReader() {} IMkvReader::~IMkvReader() {}
template <typename Type> template <typename Type>
@ -72,7 +51,7 @@ Type* SafeArrayAlloc(unsigned long long num_elements,
if (num_bytes != static_cast<size_t>(num_bytes)) if (num_bytes != static_cast<size_t>(num_bytes))
return NULL; return NULL;
return new Type[static_cast<size_t>(num_bytes)]; return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];
} }
void GetVersion(int& major, int& minor, int& build, int& revision) { void GetVersion(int& major, int& minor, int& build, int& revision) {
@ -304,7 +283,7 @@ long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
result = d; result = d;
} }
if (isinf(result) || isnan(result)) if (mkvparser::isinf(result) || mkvparser::isnan(result))
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
return 0; return 0;
@ -347,7 +326,7 @@ long UnserializeString(IMkvReader* pReader, long long pos, long long size,
delete[] str; delete[] str;
str = NULL; str = NULL;
if (size >= LONG_MAX || size < 0) if (size >= LONG_MAX || size < 0 || size > kStringElementSizeLimit)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
// +1 for '\0' terminator // +1 for '\0' terminator
@ -818,7 +797,9 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
else if ((pos + size) > total) else if ((pos + size) > total)
size = -1; size = -1;
pSegment = new Segment(pReader, idpos, pos, size); pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
if (pSegment == NULL)
return E_PARSE_FAILED;
return 0; // success return 0; // success
} }
@ -954,7 +935,11 @@ long long Segment::ParseHeaders() {
if (m_pInfo) if (m_pInfo)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
m_pInfo = new SegmentInfo(this, pos, size, element_start, element_size); m_pInfo = new (std::nothrow)
SegmentInfo(this, pos, size, element_start, element_size);
if (m_pInfo == NULL)
return -1;
const long status = m_pInfo->Parse(); const long status = m_pInfo->Parse();
@ -964,7 +949,11 @@ long long Segment::ParseHeaders() {
if (m_pTracks) if (m_pTracks)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
m_pTracks = new Tracks(this, pos, size, element_start, element_size); m_pTracks = new (std::nothrow)
Tracks(this, pos, size, element_start, element_size);
if (m_pTracks == NULL)
return -1;
const long status = m_pTracks->Parse(); const long status = m_pTracks->Parse();
@ -972,11 +961,19 @@ long long Segment::ParseHeaders() {
return status; return status;
} else if (id == libwebm::kMkvCues) { } else if (id == libwebm::kMkvCues) {
if (m_pCues == NULL) { if (m_pCues == NULL) {
m_pCues = new Cues(this, pos, size, element_start, element_size); m_pCues = new (std::nothrow)
Cues(this, pos, size, element_start, element_size);
if (m_pCues == NULL)
return -1;
} }
} else if (id == libwebm::kMkvSeekHead) { } else if (id == libwebm::kMkvSeekHead) {
if (m_pSeekHead == NULL) { if (m_pSeekHead == NULL) {
m_pSeekHead = new SeekHead(this, pos, size, element_start, element_size); m_pSeekHead = new (std::nothrow)
SeekHead(this, pos, size, element_start, element_size);
if (m_pSeekHead == NULL)
return -1;
const long status = m_pSeekHead->Parse(); const long status = m_pSeekHead->Parse();
@ -985,7 +982,11 @@ long long Segment::ParseHeaders() {
} }
} else if (id == libwebm::kMkvChapters) { } else if (id == libwebm::kMkvChapters) {
if (m_pChapters == NULL) { if (m_pChapters == NULL) {
m_pChapters = new Chapters(this, pos, size, element_start, element_size); m_pChapters = new (std::nothrow)
Chapters(this, pos, size, element_start, element_size);
if (m_pChapters == NULL)
return -1;
const long status = m_pChapters->Parse(); const long status = m_pChapters->Parse();
@ -994,7 +995,11 @@ long long Segment::ParseHeaders() {
} }
} else if (id == libwebm::kMkvTags) { } else if (id == libwebm::kMkvTags) {
if (m_pTags == NULL) { if (m_pTags == NULL) {
m_pTags = new Tags(this, pos, size, element_start, element_size); m_pTags = new (std::nothrow)
Tags(this, pos, size, element_start, element_size);
if (m_pTags == NULL)
return -1;
const long status = m_pTags->Parse(); const long status = m_pTags->Parse();
@ -1136,7 +1141,9 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
if (m_pCues == NULL) { if (m_pCues == NULL) {
const long long element_size = (pos - idpos) + size; const long long element_size = (pos - idpos) + size;
m_pCues = new Cues(this, pos, size, idpos, element_size); m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
if (m_pCues == NULL)
return -1;
} }
m_pos = pos + size; // consume payload m_pos = pos + size; // consume payload
@ -1284,9 +1291,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
pos += cluster_size; pos += cluster_size;
m_pos = pos; m_pos = pos;
// -- GODOT start --
delete pCluster;
// -- GODOT end --
if (segment_stop > 0 && m_pos > segment_stop) if (segment_stop > 0 && m_pos > segment_stop)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
@ -1344,7 +1349,9 @@ bool Segment::AppendCluster(Cluster* pCluster) {
if (count >= size) { if (count >= size) {
const long n = (size <= 0) ? 2048 : 2 * 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** q = qq;
Cluster** p = m_clusters; Cluster** p = m_clusters;
@ -1399,7 +1406,9 @@ bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
if (count >= size) { if (count >= size) {
const long n = (size <= 0) ? 2048 : 2 * 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** q = qq;
Cluster** p = m_clusters; Cluster** p = m_clusters;
@ -1468,6 +1477,8 @@ long Segment::Load() {
} }
} }
SeekHead::Entry::Entry() : id(0), pos(0), element_start(0), element_size(0) {}
SeekHead::SeekHead(Segment* pSegment, long long start, long long size_, SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
long long element_start, long long element_size) long long element_start, long long element_size)
: m_pSegment(pSegment), : m_pSegment(pSegment),
@ -1518,9 +1529,19 @@ long SeekHead::Parse() {
if (pos != stop) if (pos != stop)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
m_entries = new Entry[entry_count]; if (entry_count > 0) {
m_entries = new (std::nothrow) Entry[entry_count];
m_void_elements = new VoidElement[void_element_count]; if (m_entries == NULL)
return -1;
}
if (void_element_count > 0) {
m_void_elements = new (std::nothrow) VoidElement[void_element_count];
if (m_void_elements == NULL)
return -1;
}
// now parse the entries and void elements // now parse the entries and void elements
@ -1539,14 +1560,14 @@ long SeekHead::Parse() {
if (status < 0) // error if (status < 0) // error
return status; return status;
if (id == libwebm::kMkvSeek) { if (id == libwebm::kMkvSeek && entry_count > 0) {
if (ParseEntry(pReader, pos, size, pEntry)) { if (ParseEntry(pReader, pos, size, pEntry)) {
Entry& e = *pEntry++; Entry& e = *pEntry++;
e.element_start = idpos; e.element_start = idpos;
e.element_size = (pos + size) - idpos; e.element_size = (pos + size) - idpos;
} }
} else if (id == libwebm::kMkvVoid) { } else if (id == libwebm::kMkvVoid && void_element_count > 0) {
VoidElement& e = *pVoidElement++; VoidElement& e = *pVoidElement++;
e.element_start = idpos; e.element_start = idpos;
@ -1708,7 +1729,10 @@ long Segment::ParseCues(long long off, long long& pos, long& len) {
const long long element_size = element_stop - element_start; const long long element_size = element_stop - element_start;
m_pCues = new Cues(this, pos, size, element_start, element_size); m_pCues =
new (std::nothrow) Cues(this, pos, size, element_start, element_size);
if (m_pCues == NULL)
return -1;
return 0; // success return 0; // success
} }
@ -1750,18 +1774,7 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
if ((pos + seekIdSize) > stop) if ((pos + seekIdSize) > stop)
return false; return false;
// Note that the SeekId payload really is serialized pEntry->id = ReadID(pReader, pos, len); // payload
// as a "Matroska integer", not as a plain binary value.
// In fact, Matroska requires that ID values in the
// stream exactly match the binary representation as listed
// in the Matroska specification.
//
// This parser is more liberal, and permits IDs to have
// any width. (This could make the representation in the stream
// different from what's in the spec, but it doesn't matter here,
// since we always normalize "Matroska integer" values.)
pEntry->id = ReadUInt(pReader, pos, len); // payload
if (pEntry->id <= 0) if (pEntry->id <= 0)
return false; return false;
@ -1900,7 +1913,9 @@ bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
if (m_preload_count >= cue_points_size) { if (m_preload_count >= cue_points_size) {
const long n = (cue_points_size <= 0) ? 2048 : 2 * 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** q = qq; // beginning of target
@ -1916,7 +1931,9 @@ bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
cue_points_size = n; 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; m_cue_points[m_preload_count++] = pCP;
return true; return true;
@ -2322,7 +2339,9 @@ bool CuePoint::Load(IMkvReader* pReader) {
// << " timecode=" << m_timecode // << " timecode=" << m_timecode
// << endl; // << 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 // Now parse track positions
@ -2412,7 +2431,9 @@ bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
} }
const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const { const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
assert(pTrack); if (pTrack == NULL) {
return NULL;
}
const long long n = pTrack->GetNumber(); const long long n = pTrack->GetNumber();
@ -2917,7 +2938,10 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
const long long element_size = element_stop - element_start; const long long element_size = element_stop - element_start;
if (m_pCues == NULL) { if (m_pCues == NULL) {
m_pCues = new Cues(this, pos, size, element_start, element_size); m_pCues = new (std::nothrow)
Cues(this, pos, size, element_start, element_size);
if (m_pCues == NULL)
return false;
} }
pos += size; // consume payload pos += size; // consume payload
@ -3268,7 +3292,10 @@ bool Chapters::ExpandEditionsArray() {
const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size; const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
Edition* const editions = new Edition[size]; Edition* const editions = new (std::nothrow) Edition[size];
if (editions == NULL)
return false;
for (int idx = 0; idx < m_editions_count; ++idx) { for (int idx = 0; idx < m_editions_count; ++idx) {
m_editions[idx].ShallowCopy(editions[idx]); m_editions[idx].ShallowCopy(editions[idx]);
@ -3380,7 +3407,10 @@ bool Chapters::Edition::ExpandAtomsArray() {
const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size; const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
Atom* const atoms = new Atom[size]; Atom* const atoms = new (std::nothrow) Atom[size];
if (atoms == NULL)
return false;
for (int idx = 0; idx < m_atoms_count; ++idx) { for (int idx = 0; idx < m_atoms_count; ++idx) {
m_atoms[idx].ShallowCopy(atoms[idx]); m_atoms[idx].ShallowCopy(atoms[idx]);
@ -3565,7 +3595,10 @@ bool Chapters::Atom::ExpandDisplaysArray() {
const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size; const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
Display* const displays = new Display[size]; Display* const displays = new (std::nothrow) Display[size];
if (displays == NULL)
return false;
for (int idx = 0; idx < m_displays_count; ++idx) { for (int idx = 0; idx < m_displays_count; ++idx) {
m_displays[idx].ShallowCopy(displays[idx]); m_displays[idx].ShallowCopy(displays[idx]);
@ -3725,7 +3758,10 @@ bool Tags::ExpandTagsArray() {
const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size; const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
Tag* const tags = new Tag[size]; Tag* const tags = new (std::nothrow) Tag[size];
if (tags == NULL)
return false;
for (int idx = 0; idx < m_tags_count; ++idx) { for (int idx = 0; idx < m_tags_count; ++idx) {
m_tags[idx].ShallowCopy(tags[idx]); m_tags[idx].ShallowCopy(tags[idx]);
@ -3836,7 +3872,10 @@ bool Tags::Tag::ExpandSimpleTagsArray() {
const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size; const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
SimpleTag* const displays = new SimpleTag[size]; SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
if (displays == NULL)
return false;
for (int idx = 0; idx < m_simple_tags_count; ++idx) { for (int idx = 0; idx < m_simple_tags_count; ++idx) {
m_simple_tags[idx].ShallowCopy(displays[idx]); m_simple_tags[idx].ShallowCopy(displays[idx]);
@ -3994,7 +4033,7 @@ long SegmentInfo::Parse() {
} }
const double rollover_check = m_duration * m_timecodeScale; const double rollover_check = m_duration * m_timecodeScale;
if (rollover_check > LLONG_MAX) if (rollover_check > static_cast<double>(LLONG_MAX))
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
if (pos != stop) if (pos != stop)
@ -4085,7 +4124,7 @@ ContentEncoding::~ContentEncoding() {
} }
const ContentEncoding::ContentCompression* const ContentEncoding::ContentCompression*
ContentEncoding::GetCompressionByIndex(unsigned long idx) const { ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
const ptrdiff_t count = compression_entries_end_ - compression_entries_; const ptrdiff_t count = compression_entries_end_ - compression_entries_;
assert(count >= 0); assert(count >= 0);
@ -4181,12 +4220,20 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
return -1; return -1;
if (compression_count > 0) { if (compression_count > 0) {
compression_entries_ = new ContentCompression*[compression_count]; compression_entries_ =
new (std::nothrow) ContentCompression*[compression_count];
if (!compression_entries_)
return -1;
compression_entries_end_ = compression_entries_; compression_entries_end_ = compression_entries_;
} }
if (encryption_count > 0) { if (encryption_count > 0) {
encryption_entries_ = new ContentEncryption*[encryption_count]; encryption_entries_ =
new (std::nothrow) ContentEncryption*[encryption_count];
if (!encryption_entries_) {
delete[] compression_entries_;
return -1;
}
encryption_entries_end_ = encryption_entries_; encryption_entries_end_ = encryption_entries_;
} }
@ -4206,7 +4253,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
} else if (id == libwebm::kMkvContentEncodingType) { } else if (id == libwebm::kMkvContentEncodingType) {
encoding_type_ = UnserializeUInt(pReader, pos, size); encoding_type_ = UnserializeUInt(pReader, pos, size);
} else if (id == libwebm::kMkvContentCompression) { } else if (id == libwebm::kMkvContentCompression) {
ContentCompression* const compression = new ContentCompression(); ContentCompression* const compression =
new (std::nothrow) ContentCompression();
if (!compression)
return -1;
status = ParseCompressionEntry(pos, size, pReader, compression); status = ParseCompressionEntry(pos, size, pReader, compression);
if (status) { if (status) {
@ -4215,7 +4265,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
} }
*compression_entries_end_++ = compression; *compression_entries_end_++ = compression;
} else if (id == libwebm::kMkvContentEncryption) { } else if (id == libwebm::kMkvContentEncryption) {
ContentEncryption* const encryption = new ContentEncryption(); ContentEncryption* const encryption =
new (std::nothrow) ContentEncryption();
if (!encryption)
return -1;
status = ParseEncryptionEntry(pos, size, pReader, encryption); status = ParseEncryptionEntry(pos, size, pReader, encryption);
if (status) { if (status) {
@ -4421,7 +4474,11 @@ long Track::Create(Segment* pSegment, const Info& info, long long element_start,
if (pResult) if (pResult)
return -1; return -1;
Track* const pTrack = new Track(pSegment, element_start, element_size); Track* const pTrack =
new (std::nothrow) Track(pSegment, element_start, element_size);
if (pTrack == NULL)
return -1; // generic error
const int status = info.Copy(pTrack->m_info); const int status = info.Copy(pTrack->m_info);
@ -4873,7 +4930,10 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
if (count <= 0) if (count <= 0)
return -1; return -1;
content_encoding_entries_ = new ContentEncoding*[count]; content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count];
if (!content_encoding_entries_)
return -1;
content_encoding_entries_end_ = content_encoding_entries_; content_encoding_entries_end_ = content_encoding_entries_;
pos = start; pos = start;
@ -4885,7 +4945,10 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
// pos now designates start of element // pos now designates start of element
if (id == libwebm::kMkvContentEncoding) { if (id == libwebm::kMkvContentEncoding) {
ContentEncoding* const content_encoding = new ContentEncoding(); ContentEncoding* const content_encoding =
new (std::nothrow) ContentEncoding();
if (!content_encoding)
return -1;
status = content_encoding->ParseContentEncodingEntry(pos, size, pReader); status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
if (status) { if (status) {
@ -4919,20 +4982,27 @@ bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
if (!reader) if (!reader)
return false; return false;
my_auto_ptr<PrimaryChromaticity> chromaticity_ptr(*chromaticity ? *chromaticity : new PrimaryChromaticity()); if (!*chromaticity)
*chromaticity = new PrimaryChromaticity();
float* value = is_x ? &chromaticity_ptr->x : &chromaticity_ptr->y; if (!*chromaticity)
return false;
PrimaryChromaticity* pc = *chromaticity;
float* value = is_x ? &pc->x : &pc->y;
double parser_value = 0; double parser_value = 0;
const long long value_parse_status = const long long parse_status =
UnserializeFloat(reader, read_pos, value_size, parser_value); UnserializeFloat(reader, read_pos, value_size, parser_value);
// Valid range is [0, 1]. Make sure the double is representable as a float
// before casting.
if (parse_status < 0 || parser_value < 0.0 || parser_value > 1.0 ||
(parser_value > 0.0 && parser_value < FLT_MIN))
return false;
*value = static_cast<float>(parser_value); *value = static_cast<float>(parser_value);
if (value_parse_status < 0 || *value < 0.0 || *value > 1.0)
return false;
*chromaticity = chromaticity_ptr.release();
return true; return true;
} }
@ -4941,7 +5011,9 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
if (!reader || *mm) if (!reader || *mm)
return false; return false;
my_auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata()); std::unique_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
if (!mm_ptr.get())
return false;
const long long mm_end = mm_start + mm_size; const long long mm_end = mm_start + mm_size;
long long read_pos = mm_start; long long read_pos = mm_start;
@ -4959,6 +5031,10 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
double value = 0; double value = 0;
const long long value_parse_status = const long long value_parse_status =
UnserializeFloat(reader, read_pos, child_size, value); UnserializeFloat(reader, read_pos, child_size, value);
if (value < -FLT_MAX || value > FLT_MAX ||
(value > 0.0 && value < FLT_MIN)) {
return false;
}
mm_ptr->luminance_max = static_cast<float>(value); mm_ptr->luminance_max = static_cast<float>(value);
if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 || if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 ||
mm_ptr->luminance_max > 9999.99) { mm_ptr->luminance_max > 9999.99) {
@ -4968,6 +5044,10 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
double value = 0; double value = 0;
const long long value_parse_status = const long long value_parse_status =
UnserializeFloat(reader, read_pos, child_size, value); UnserializeFloat(reader, read_pos, child_size, value);
if (value < -FLT_MAX || value > FLT_MAX ||
(value > 0.0 && value < FLT_MIN)) {
return false;
}
mm_ptr->luminance_min = static_cast<float>(value); mm_ptr->luminance_min = static_cast<float>(value);
if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 || if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 ||
mm_ptr->luminance_min > 999.9999) { mm_ptr->luminance_min > 999.9999) {
@ -5020,7 +5100,9 @@ bool Colour::Parse(IMkvReader* reader, long long colour_start,
if (!reader || *colour) if (!reader || *colour)
return false; return false;
my_auto_ptr<Colour> colour_ptr(new Colour()); std::unique_ptr<Colour> colour_ptr(new Colour());
if (!colour_ptr.get())
return false;
const long long colour_end = colour_start + colour_size; const long long colour_end = colour_start + colour_size;
long long read_pos = colour_start; long long read_pos = colour_start;
@ -5111,11 +5193,94 @@ bool Colour::Parse(IMkvReader* reader, long long colour_start,
return true; return true;
} }
bool Projection::Parse(IMkvReader* reader, long long start, long long size,
Projection** projection) {
if (!reader || *projection)
return false;
std::unique_ptr<Projection> projection_ptr(new Projection());
if (!projection_ptr.get())
return false;
const long long end = start + size;
long long read_pos = start;
while (read_pos < end) {
long long child_id = 0;
long long child_size = 0;
const long long status =
ParseElementHeader(reader, read_pos, end, child_id, child_size);
if (status < 0)
return false;
if (child_id == libwebm::kMkvProjectionType) {
long long projection_type = kTypeNotPresent;
projection_type = UnserializeUInt(reader, read_pos, child_size);
if (projection_type < 0)
return false;
projection_ptr->type = static_cast<ProjectionType>(projection_type);
} else if (child_id == libwebm::kMkvProjectionPrivate) {
unsigned char* data = SafeArrayAlloc<unsigned char>(1, child_size);
if (data == NULL)
return false;
const int status =
reader->Read(read_pos, static_cast<long>(child_size), data);
if (status) {
delete[] data;
return false;
}
projection_ptr->private_data = data;
projection_ptr->private_data_length = static_cast<size_t>(child_size);
} else {
double value = 0;
const long long value_parse_status =
UnserializeFloat(reader, read_pos, child_size, value);
// Make sure value is representable as a float before casting.
if (value_parse_status < 0 || value < -FLT_MAX || value > FLT_MAX ||
(value > 0.0 && value < FLT_MIN)) {
return false;
}
switch (child_id) {
case libwebm::kMkvProjectionPoseYaw:
projection_ptr->pose_yaw = static_cast<float>(value);
break;
case libwebm::kMkvProjectionPosePitch:
projection_ptr->pose_pitch = static_cast<float>(value);
break;
case libwebm::kMkvProjectionPoseRoll:
projection_ptr->pose_roll = static_cast<float>(value);
break;
default:
return false;
}
}
read_pos += child_size;
if (read_pos > end)
return false;
}
*projection = projection_ptr.release();
return true;
}
VideoTrack::VideoTrack(Segment* pSegment, long long element_start, VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
long long element_size) long long element_size)
: Track(pSegment, element_start, element_size), m_colour(NULL) {} : Track(pSegment, element_start, element_size),
m_colour(NULL),
m_projection(NULL) {}
VideoTrack::~VideoTrack() { delete m_colour; } VideoTrack::~VideoTrack() {
delete m_colour;
delete m_projection;
}
long VideoTrack::Parse(Segment* pSegment, const Info& info, long VideoTrack::Parse(Segment* pSegment, const Info& info,
long long element_start, long long element_size, long long element_start, long long element_size,
@ -5147,6 +5312,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
const long long stop = pos + s.size; const long long stop = pos + s.size;
Colour* colour = NULL; Colour* colour = NULL;
Projection* projection = NULL;
while (pos < stop) { while (pos < stop) {
long long id, size; long long id, size;
@ -5197,6 +5363,9 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
} else if (id == libwebm::kMkvColour) { } else if (id == libwebm::kMkvColour) {
if (!Colour::Parse(pReader, pos, size, &colour)) if (!Colour::Parse(pReader, pos, size, &colour))
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
} else if (id == libwebm::kMkvProjection) {
if (!Projection::Parse(pReader, pos, size, &projection))
return E_FILE_FORMAT_INVALID;
} }
pos += size; // consume payload pos += size; // consume payload
@ -5207,7 +5376,11 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
if (pos != stop) if (pos != stop)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
VideoTrack* const pTrack = new VideoTrack(pSegment, element_start, element_size); VideoTrack* const pTrack =
new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
if (pTrack == NULL)
return -1; // generic error
const int status = info.Copy(pTrack->m_info); const int status = info.Copy(pTrack->m_info);
@ -5224,6 +5397,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
pTrack->m_stereo_mode = stereo_mode; pTrack->m_stereo_mode = stereo_mode;
pTrack->m_rate = rate; pTrack->m_rate = rate;
pTrack->m_colour = colour; pTrack->m_colour = colour;
pTrack->m_projection = projection;
pResult = pTrack; pResult = pTrack;
return 0; // success return 0; // success
@ -5324,6 +5498,8 @@ long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
Colour* VideoTrack::GetColour() const { return m_colour; } Colour* VideoTrack::GetColour() const { return m_colour; }
Projection* VideoTrack::GetProjection() const { return m_projection; }
long long VideoTrack::GetWidth() const { return m_width; } long long VideoTrack::GetWidth() const { return m_width; }
long long VideoTrack::GetHeight() const { return m_height; } long long VideoTrack::GetHeight() const { return m_height; }
@ -5406,7 +5582,11 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
if (pos != stop) if (pos != stop)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
AudioTrack* const pTrack = new AudioTrack(pSegment, element_start, element_size); AudioTrack* const pTrack =
new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
if (pTrack == NULL)
return -1; // generic error
const int status = info.Copy(pTrack->m_info); const int status = info.Copy(pTrack->m_info);
@ -5474,7 +5654,11 @@ long Tracks::Parse() {
if (count <= 0) if (count <= 0)
return 0; // success return 0; // success
m_trackEntries = new Track*[count]; m_trackEntries = new (std::nothrow) Track*[count];
if (m_trackEntries == NULL)
return -1;
m_trackEntriesEnd = m_trackEntries; m_trackEntriesEnd = m_trackEntries;
pos = m_start; pos = m_start;
@ -6577,7 +6761,10 @@ Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
const long long element_start = pSegment->m_start + off; const long long element_start = pSegment->m_start + off;
return new Cluster(pSegment, idx, element_start); Cluster* const pCluster =
new (std::nothrow) Cluster(pSegment, idx, element_start);
return pCluster;
} }
Cluster::Cluster() Cluster::Cluster()
@ -6606,8 +6793,10 @@ Cluster::Cluster(Segment* pSegment, long idx, long long element_start
{} {}
Cluster::~Cluster() { Cluster::~Cluster() {
if (m_entries_count <= 0) if (m_entries_count <= 0) {
delete[] m_entries;
return; return;
}
BlockEntry** i = m_entries; BlockEntry** i = m_entries;
BlockEntry** const j = m_entries + m_entries_count; BlockEntry** const j = m_entries + m_entries_count;
@ -6920,7 +7109,9 @@ long Cluster::CreateBlock(long long id,
assert(m_entries_size == 0); assert(m_entries_size == 0);
m_entries_size = 1024; 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; m_entries_count = 0;
} else { } else {
@ -6931,7 +7122,9 @@ long Cluster::CreateBlock(long long id,
if (m_entries_count >= m_entries_size) { if (m_entries_count >= m_entries_size) {
const long entries_size = 2 * m_entries_size; const long entries_size = 2 * m_entries_size;
BlockEntry** const entries = new BlockEntry*[entries_size]; BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
if (entries == NULL)
return -1;
BlockEntry** src = m_entries; BlockEntry** src = m_entries;
BlockEntry** const src_end = src + m_entries_count; BlockEntry** const src_end = src + m_entries_count;
@ -7040,7 +7233,11 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
BlockEntry** const ppEntry = m_entries + idx; BlockEntry** const ppEntry = m_entries + idx;
BlockEntry*& pEntry = *ppEntry; BlockEntry*& pEntry = *ppEntry;
pEntry = new BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding); pEntry = new (std::nothrow)
BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
if (pEntry == NULL)
return -1; // generic error
BlockGroup* const p = static_cast<BlockGroup*>(pEntry); BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
@ -7068,7 +7265,10 @@ long Cluster::CreateSimpleBlock(long long st, long long sz) {
BlockEntry** const ppEntry = m_entries + idx; BlockEntry** const ppEntry = m_entries + idx;
BlockEntry*& pEntry = *ppEntry; BlockEntry*& pEntry = *ppEntry;
pEntry = new SimpleBlock(this, idx, st, sz); pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
if (pEntry == NULL)
return -1; // generic error
SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry); SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
@ -7463,7 +7663,9 @@ long Block::Parse(const Cluster* pCluster) {
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
m_frame_count = 1; 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]; Frame& f = m_frames[0];
f.pos = pos; f.pos = pos;
@ -7494,7 +7696,9 @@ long Block::Parse(const Cluster* pCluster) {
m_frame_count = int(biased_count) + 1; m_frame_count = int(biased_count) + 1;
m_frames = new Frame[m_frame_count]; m_frames = new (std::nothrow) Frame[m_frame_count];
if (m_frames == NULL)
return -1;
if (!m_frames) if (!m_frames)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
@ -7703,6 +7907,10 @@ long Block::Parse(const Cluster* pCluster) {
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
curr.len = static_cast<long>(frame_size); curr.len = static_cast<long>(frame_size);
// Check if size + curr.len could overflow.
if (size > LLONG_MAX - curr.len) {
return E_FILE_FORMAT_INVALID;
}
size += curr.len; // contribution of this frame size += curr.len; // contribution of this frame
--frame_count; --frame_count;
@ -7743,7 +7951,6 @@ long Block::Parse(const Cluster* pCluster) {
pf = m_frames; pf = m_frames;
while (pf != pf_end) { while (pf != pf_end) {
Frame& f = *pf++; Frame& f = *pf++;
assert((pos + f.len) <= stop);
if ((pos + f.len) > stop) if ((pos + f.len) > stop)
return E_FILE_FORMAT_INVALID; return E_FILE_FORMAT_INVALID;
@ -7765,6 +7972,11 @@ long long Block::GetTimeCode(const Cluster* pCluster) const {
const long long tc0 = pCluster->GetTimeCode(); const long long tc0 = pCluster->GetTimeCode();
assert(tc0 >= 0); assert(tc0 >= 0);
// Check if tc0 + m_timecode would overflow.
if (tc0 < 0 || LLONG_MAX - tc0 < m_timecode) {
return -1;
}
const long long tc = tc0 + m_timecode; const long long tc = tc0 + m_timecode;
return tc; // unscaled timecode units return tc; // unscaled timecode units
@ -7782,6 +7994,10 @@ long long Block::GetTime(const Cluster* pCluster) const {
const long long scale = pInfo->GetTimeCodeScale(); const long long scale = pInfo->GetTimeCodeScale();
assert(scale >= 1); assert(scale >= 1);
// Check if tc * scale could overflow.
if (tc != 0 && scale > LLONG_MAX / tc) {
return -1;
}
const long long ns = tc * scale; const long long ns = tc * scale;
return ns; return ns;

View file

@ -8,7 +8,7 @@
#ifndef MKVPARSER_MKVPARSER_H_ #ifndef MKVPARSER_MKVPARSER_H_
#define MKVPARSER_MKVPARSER_H_ #define MKVPARSER_MKVPARSER_H_
#include <stddef.h> #include <cstddef>
namespace mkvparser { namespace mkvparser {
@ -21,6 +21,7 @@ class IMkvReader {
virtual int Read(long long pos, long len, unsigned char* buf) = 0; virtual int Read(long long pos, long len, unsigned char* buf) = 0;
virtual int Length(long long* total, long long* available) = 0; virtual int Length(long long* total, long long* available) = 0;
public:
virtual ~IMkvReader(); virtual ~IMkvReader();
}; };
@ -472,6 +473,34 @@ struct Colour {
MasteringMetadata* mastering_metadata; MasteringMetadata* mastering_metadata;
}; };
struct Projection {
enum ProjectionType {
kTypeNotPresent = -1,
kRectangular = 0,
kEquirectangular = 1,
kCubeMap = 2,
kMesh = 3,
};
static const float kValueNotPresent;
Projection()
: type(kTypeNotPresent),
private_data(NULL),
private_data_length(0),
pose_yaw(kValueNotPresent),
pose_pitch(kValueNotPresent),
pose_roll(kValueNotPresent) {}
~Projection() { delete[] private_data; }
static bool Parse(IMkvReader* reader, long long element_start,
long long element_size, Projection** projection);
ProjectionType type;
unsigned char* private_data;
size_t private_data_length;
float pose_yaw;
float pose_pitch;
float pose_roll;
};
class VideoTrack : public Track { class VideoTrack : public Track {
VideoTrack(const VideoTrack&); VideoTrack(const VideoTrack&);
VideoTrack& operator=(const VideoTrack&); VideoTrack& operator=(const VideoTrack&);
@ -496,6 +525,8 @@ class VideoTrack : public Track {
Colour* GetColour() const; Colour* GetColour() const;
Projection* GetProjection() const;
private: private:
long long m_width; long long m_width;
long long m_height; long long m_height;
@ -507,6 +538,7 @@ class VideoTrack : public Track {
double m_rate; double m_rate;
Colour* m_colour; Colour* m_colour;
Projection* m_projection;
}; };
class AudioTrack : public Track { class AudioTrack : public Track {
@ -812,6 +844,8 @@ class SeekHead {
long Parse(); long Parse();
struct Entry { struct Entry {
Entry();
// the SeekHead entry payload // the SeekHead entry payload
long long id; long long id;
long long pos; long long pos;