From e71f1099104e0420ebdd458b61225f7c29d79358 Mon Sep 17 00:00:00 2001 From: ShyRed Date: Fri, 9 Mar 2018 17:28:08 +0100 Subject: [PATCH] Update libwebm Update of libwebm. Up-to-date version of libwebm contains several bugfixes that allow playback of files that would crash Godot otherwise. --- modules/webm/SCsub | 4 + .../libsimplewebm/libwebm/README.libvpx | 2 +- .../libsimplewebm/libwebm/common/webmids.h | 8 + .../libwebm/mkvparser/mkvparser.cc | 432 +++++++++++++----- .../libwebm/mkvparser/mkvparser.h | 36 +- 5 files changed, 372 insertions(+), 110 deletions(-) diff --git a/modules/webm/SCsub b/modules/webm/SCsub index 2f1a28a54ca5..33561da0988a 100644 --- a/modules/webm/SCsub +++ b/modules/webm/SCsub @@ -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.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 if env['builtin_libogg']: env_webm.Append(CPPPATH=["#thirdparty/libogg"]) diff --git a/thirdparty/libsimplewebm/libwebm/README.libvpx b/thirdparty/libsimplewebm/libwebm/README.libvpx index ae62f365253c..1aa93b75aa23 100644 --- a/thirdparty/libsimplewebm/libwebm/README.libvpx +++ b/thirdparty/libsimplewebm/libwebm/README.libvpx @@ -1,5 +1,5 @@ URL: https://chromium.googlesource.com/webm/libwebm -Version: 32d5ac49414a8914ec1e1f285f3f927c6e8ec29d +Version: d7c62173ff6b4a5e0a2f86683a5b67db98cf09bf License: BSD License File: LICENSE.txt diff --git a/thirdparty/libsimplewebm/libwebm/common/webmids.h b/thirdparty/libsimplewebm/libwebm/common/webmids.h index 32a0c5fb9111..89d722a71bcb 100644 --- a/thirdparty/libsimplewebm/libwebm/common/webmids.h +++ b/thirdparty/libsimplewebm/libwebm/common/webmids.h @@ -124,6 +124,14 @@ enum MkvId { kMkvLuminanceMin = 0x55DA, // end mastering metadata // end colour + // projection + kMkvProjection = 0x7670, + kMkvProjectionType = 0x7671, + kMkvProjectionPrivate = 0x7672, + kMkvProjectionPoseYaw = 0x7673, + kMkvProjectionPosePitch = 0x7674, + kMkvProjectionPoseRoll = 0x7675, + // end projection // audio kMkvAudio = 0xE1, kMkvSamplingFrequency = 0xB5, diff --git a/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.cc b/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.cc index d2375edb3beb..e7b76f7da110 100644 --- a/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.cc +++ b/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.cc @@ -12,51 +12,30 @@ #define MSC_COMPAT #endif -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include "common/webmids.h" namespace mkvparser { +const long long kStringElementSizeLimit = 20 * 1000 * 1000; const float MasteringMetadata::kValueNotPresent = FLT_MAX; const long long Colour::kValueNotPresent = LLONG_MAX; +const float Projection::kValueNotPresent = FLT_MAX; #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 -template -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() {} template @@ -72,7 +51,7 @@ Type* SafeArrayAlloc(unsigned long long num_elements, if (num_bytes != static_cast(num_bytes)) return NULL; - return new Type[static_cast(num_bytes)]; + return new (std::nothrow) Type[static_cast(num_bytes)]; } 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; } - if (isinf(result) || isnan(result)) + if (mkvparser::isinf(result) || mkvparser::isnan(result)) return E_FILE_FORMAT_INVALID; return 0; @@ -347,7 +326,7 @@ long UnserializeString(IMkvReader* pReader, long long pos, long long size, delete[] str; str = NULL; - if (size >= LONG_MAX || size < 0) + if (size >= LONG_MAX || size < 0 || size > kStringElementSizeLimit) return E_FILE_FORMAT_INVALID; // +1 for '\0' terminator @@ -818,7 +797,9 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos, else if ((pos + size) > total) 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 } @@ -954,7 +935,11 @@ long long Segment::ParseHeaders() { if (m_pInfo) 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(); @@ -964,7 +949,11 @@ long long Segment::ParseHeaders() { if (m_pTracks) 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(); @@ -972,11 +961,19 @@ long long Segment::ParseHeaders() { return status; } else if (id == libwebm::kMkvCues) { 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) { 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(); @@ -985,7 +982,11 @@ long long Segment::ParseHeaders() { } } else if (id == libwebm::kMkvChapters) { 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(); @@ -994,7 +995,11 @@ long long Segment::ParseHeaders() { } } else if (id == libwebm::kMkvTags) { 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(); @@ -1136,7 +1141,9 @@ long Segment::DoLoadCluster(long long& pos, long& len) { if (m_pCues == NULL) { 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 @@ -1284,9 +1291,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) { pos += cluster_size; m_pos = pos; - // -- GODOT start -- - delete pCluster; - // -- GODOT end -- + if (segment_stop > 0 && m_pos > segment_stop) return E_FILE_FORMAT_INVALID; @@ -1344,7 +1349,9 @@ bool Segment::AppendCluster(Cluster* pCluster) { 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; @@ -1399,7 +1406,9 @@ bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) { 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; @@ -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_, long long element_start, long long element_size) : m_pSegment(pSegment), @@ -1518,9 +1529,19 @@ long SeekHead::Parse() { if (pos != stop) 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 @@ -1539,14 +1560,14 @@ long SeekHead::Parse() { if (status < 0) // error return status; - if (id == libwebm::kMkvSeek) { + if (id == libwebm::kMkvSeek && entry_count > 0) { if (ParseEntry(pReader, pos, size, pEntry)) { Entry& e = *pEntry++; e.element_start = idpos; e.element_size = (pos + size) - idpos; } - } else if (id == libwebm::kMkvVoid) { + } else if (id == libwebm::kMkvVoid && void_element_count > 0) { VoidElement& e = *pVoidElement++; 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; - 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 } @@ -1750,18 +1774,7 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, if ((pos + seekIdSize) > stop) return false; - // Note that the SeekId payload really is serialized - // 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 + pEntry->id = ReadID(pReader, pos, len); // payload if (pEntry->id <= 0) return false; @@ -1900,7 +1913,9 @@ bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { 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 @@ -1916,7 +1931,9 @@ bool 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; @@ -2322,7 +2339,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 @@ -2412,7 +2431,9 @@ bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, } const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const { - assert(pTrack); + if (pTrack == NULL) { + return NULL; + } 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; 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 @@ -3268,7 +3292,10 @@ bool Chapters::ExpandEditionsArray() { 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) { 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; - 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) { 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; - 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) { 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; - 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) { 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; - 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) { m_simple_tags[idx].ShallowCopy(displays[idx]); @@ -3994,7 +4033,7 @@ long SegmentInfo::Parse() { } const double rollover_check = m_duration * m_timecodeScale; - if (rollover_check > LLONG_MAX) + if (rollover_check > static_cast(LLONG_MAX)) return E_FILE_FORMAT_INVALID; if (pos != stop) @@ -4085,7 +4124,7 @@ ContentEncoding::~ContentEncoding() { } const ContentEncoding::ContentCompression* - ContentEncoding::GetCompressionByIndex(unsigned long idx) const { +ContentEncoding::GetCompressionByIndex(unsigned long idx) const { const ptrdiff_t count = compression_entries_end_ - compression_entries_; assert(count >= 0); @@ -4181,12 +4220,20 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, return -1; 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_; } 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_; } @@ -4206,7 +4253,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, } else if (id == libwebm::kMkvContentEncodingType) { encoding_type_ = UnserializeUInt(pReader, pos, size); } 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); if (status) { @@ -4215,7 +4265,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, } *compression_entries_end_++ = compression; } 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); if (status) { @@ -4421,7 +4474,11 @@ long Track::Create(Segment* pSegment, const Info& info, long long element_start, if (pResult) 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); @@ -4873,7 +4930,10 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { if (count <= 0) 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_; pos = start; @@ -4885,7 +4945,10 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { // pos now designates start of element 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); if (status) { @@ -4919,20 +4982,27 @@ bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos, if (!reader) return false; - my_auto_ptr 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; - const long long value_parse_status = + const long long parse_status = 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(parser_value); - if (value_parse_status < 0 || *value < 0.0 || *value > 1.0) - return false; - - *chromaticity = chromaticity_ptr.release(); return true; } @@ -4941,7 +5011,9 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start, if (!reader || *mm) return false; - my_auto_ptr mm_ptr(new MasteringMetadata()); + std::unique_ptr mm_ptr(new MasteringMetadata()); + if (!mm_ptr.get()) + return false; const long long mm_end = mm_start + mm_size; long long read_pos = mm_start; @@ -4959,6 +5031,10 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start, double value = 0; const long long value_parse_status = 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(value); if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 || mm_ptr->luminance_max > 9999.99) { @@ -4968,6 +5044,10 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start, double value = 0; const long long value_parse_status = 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(value); if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 || mm_ptr->luminance_min > 999.9999) { @@ -5020,7 +5100,9 @@ bool Colour::Parse(IMkvReader* reader, long long colour_start, if (!reader || *colour) return false; - my_auto_ptr colour_ptr(new Colour()); + std::unique_ptr colour_ptr(new Colour()); + if (!colour_ptr.get()) + return false; const long long colour_end = colour_start + colour_size; long long read_pos = colour_start; @@ -5111,11 +5193,94 @@ bool Colour::Parse(IMkvReader* reader, long long colour_start, return true; } +bool Projection::Parse(IMkvReader* reader, long long start, long long size, + Projection** projection) { + if (!reader || *projection) + return false; + + std::unique_ptr 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(projection_type); + } else if (child_id == libwebm::kMkvProjectionPrivate) { + unsigned char* data = SafeArrayAlloc(1, child_size); + + if (data == NULL) + return false; + + const int status = + reader->Read(read_pos, static_cast(child_size), data); + + if (status) { + delete[] data; + return false; + } + + projection_ptr->private_data = data; + projection_ptr->private_data_length = static_cast(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(value); + break; + case libwebm::kMkvProjectionPosePitch: + projection_ptr->pose_pitch = static_cast(value); + break; + case libwebm::kMkvProjectionPoseRoll: + projection_ptr->pose_roll = static_cast(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, 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 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; Colour* colour = NULL; + Projection* projection = NULL; while (pos < stop) { long long id, size; @@ -5197,6 +5363,9 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, } else if (id == libwebm::kMkvColour) { if (!Colour::Parse(pReader, pos, size, &colour)) 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 @@ -5207,7 +5376,11 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, if (pos != stop) 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); @@ -5224,6 +5397,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, pTrack->m_stereo_mode = stereo_mode; pTrack->m_rate = rate; pTrack->m_colour = colour; + pTrack->m_projection = projection; pResult = pTrack; 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; } +Projection* VideoTrack::GetProjection() const { return m_projection; } + long long VideoTrack::GetWidth() const { return m_width; } long long VideoTrack::GetHeight() const { return m_height; } @@ -5406,7 +5582,11 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info, if (pos != stop) 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); @@ -5474,7 +5654,11 @@ long Tracks::Parse() { if (count <= 0) 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; 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; - return new Cluster(pSegment, idx, element_start); + Cluster* const pCluster = + new (std::nothrow) Cluster(pSegment, idx, element_start); + + return pCluster; } Cluster::Cluster() @@ -6606,8 +6793,10 @@ Cluster::Cluster(Segment* pSegment, long idx, long long element_start {} Cluster::~Cluster() { - if (m_entries_count <= 0) + if (m_entries_count <= 0) { + delete[] m_entries; return; + } BlockEntry** i = m_entries; BlockEntry** const j = m_entries + m_entries_count; @@ -6920,7 +7109,9 @@ long Cluster::CreateBlock(long long id, 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 { @@ -6931,7 +7122,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]; + 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; @@ -7040,7 +7233,11 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size, BlockEntry** const ppEntry = m_entries + idx; 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(pEntry); @@ -7068,7 +7265,10 @@ long Cluster::CreateSimpleBlock(long long st, long long sz) { BlockEntry** const ppEntry = m_entries + idx; 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(pEntry); @@ -7463,7 +7663,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; @@ -7494,7 +7696,9 @@ long Block::Parse(const Cluster* pCluster) { 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) return E_FILE_FORMAT_INVALID; @@ -7703,6 +7907,10 @@ long Block::Parse(const Cluster* pCluster) { return E_FILE_FORMAT_INVALID; curr.len = static_cast(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 --frame_count; @@ -7743,7 +7951,6 @@ long Block::Parse(const Cluster* pCluster) { pf = m_frames; while (pf != pf_end) { Frame& f = *pf++; - assert((pos + f.len) <= stop); if ((pos + f.len) > stop) return E_FILE_FORMAT_INVALID; @@ -7765,6 +7972,11 @@ long long Block::GetTimeCode(const Cluster* pCluster) const { const long long tc0 = pCluster->GetTimeCode(); 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; return tc; // unscaled timecode units @@ -7782,6 +7994,10 @@ long long Block::GetTime(const Cluster* pCluster) const { const long long scale = pInfo->GetTimeCodeScale(); assert(scale >= 1); + // Check if tc * scale could overflow. + if (tc != 0 && scale > LLONG_MAX / tc) { + return -1; + } const long long ns = tc * scale; return ns; diff --git a/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.h b/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.h index 1ef274b162ef..6dce7e50ba03 100644 --- a/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.h +++ b/thirdparty/libsimplewebm/libwebm/mkvparser/mkvparser.h @@ -8,7 +8,7 @@ #ifndef MKVPARSER_MKVPARSER_H_ #define MKVPARSER_MKVPARSER_H_ -#include +#include namespace mkvparser { @@ -21,6 +21,7 @@ class IMkvReader { virtual int Read(long long pos, long len, unsigned char* buf) = 0; virtual int Length(long long* total, long long* available) = 0; + public: virtual ~IMkvReader(); }; @@ -472,6 +473,34 @@ struct Colour { 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 { VideoTrack(const VideoTrack&); VideoTrack& operator=(const VideoTrack&); @@ -496,6 +525,8 @@ class VideoTrack : public Track { Colour* GetColour() const; + Projection* GetProjection() const; + private: long long m_width; long long m_height; @@ -507,6 +538,7 @@ class VideoTrack : public Track { double m_rate; Colour* m_colour; + Projection* m_projection; }; class AudioTrack : public Track { @@ -812,6 +844,8 @@ class SeekHead { long Parse(); struct Entry { + Entry(); + // the SeekHead entry payload long long id; long long pos;