Skip to content

Commit

Permalink
mkvinfo: fix handling of elements outside a segment
Browse files Browse the repository at this point in the history
Fixes #1183.
  • Loading branch information
mbunkus committed May 30, 2015
1 parent e95a8fc commit c035397
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 82 deletions.
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2015-05-30 Moritz Bunkus <moritz@bunkus.org>

* mkvinfo: bug fix: fixed a crash with certain types of invalid
Matroska files. Part of the fix for #1183.

2015-05-26 Moritz Bunkus <moritz@bunkus.org>

* all: bug fix: removed some unused code thereby fixing
Expand Down
21 changes: 18 additions & 3 deletions src/common/kax_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ kax_file_c::kax_file_c(mm_io_cptr &in)
, m_resynced(false)
, m_resync_start_pos(0)
, m_file_size(m_in->get_size())
, m_segment_end{}
, m_timecode_scale{TIMECODE_SCALE}
, m_last_timecode{-1}
, m_es(new EbmlStream(*m_in))
Expand All @@ -39,6 +40,9 @@ kax_file_c::kax_file_c(mm_io_cptr &in)
{
}

kax_file_c::~kax_file_c() {
}

EbmlElement *
kax_file_c::read_next_level1_element(uint32_t wanted_id,
bool report_cluster_timecode) {
Expand Down Expand Up @@ -69,11 +73,11 @@ kax_file_c::read_next_level1_element(uint32_t wanted_id,
return nullptr;
}

kax_file_c::~kax_file_c() {
}

EbmlElement *
kax_file_c::read_next_level1_element_internal(uint32_t wanted_id) {
if (m_segment_end && (m_in->getFilePointer() >= m_segment_end))
return nullptr;

m_resynced = false;
m_resync_start_pos = 0;

Expand Down Expand Up @@ -133,6 +137,9 @@ kax_file_c::read_next_level1_element_internal(uint32_t wanted_id) {

EbmlElement *
kax_file_c::read_one_element() {
if (m_segment_end && (m_in->getFilePointer() >= m_segment_end))
return nullptr;

int upper_lvl_el = 0;
EbmlElement *l1 = m_es->FindNextElement(EBML_CLASS_CONTEXT(KaxSegment), upper_lvl_el, 0xFFFFFFFFL, true);

Expand Down Expand Up @@ -192,6 +199,9 @@ kax_file_c::resync_to_level1_element(uint32_t wanted_id) {

EbmlElement *
kax_file_c::resync_to_level1_element_internal(uint32_t wanted_id) {
if (m_segment_end && (m_in->getFilePointer() >= m_segment_end))
return nullptr;

m_resynced = true;
m_resync_start_pos = m_in->getFilePointer();

Expand Down Expand Up @@ -323,3 +333,8 @@ void
kax_file_c::set_last_timecode(int64_t last_timecode) {
m_last_timecode = last_timecode;
}

void
kax_file_c::set_segment_end(EbmlElement const &segment) {
m_segment_end = segment.IsFiniteSize() ? segment.GetElementPosition() + segment.HeadSize() + segment.GetSize() : m_in->get_size();
}
3 changes: 2 additions & 1 deletion src/common/kax_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class kax_file_c {
protected:
mm_io_cptr m_in;
bool m_resynced;
uint64_t m_resync_start_pos, m_file_size;
uint64_t m_resync_start_pos, m_file_size, m_segment_end;
int64_t m_timecode_scale, m_last_timecode;
std::shared_ptr<EbmlStream> m_es;

Expand All @@ -53,6 +53,7 @@ class kax_file_c {

virtual void set_timecode_scale(int64_t timecode_scale);
virtual void set_last_timecode(int64_t last_timecode);
virtual void set_segment_end(EbmlElement const &segment);

protected:
virtual EbmlElement *read_one_element();
Expand Down
155 changes: 77 additions & 78 deletions src/info/mkvinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1560,6 +1560,67 @@ handle_ebml_head(EbmlElement *l0,
}
}

void
handle_segment(EbmlElement *l0,
mm_io_cptr &in,
EbmlStream *es) {
auto file_size = in->get_size();
auto l1 = static_cast<EbmlElement *>(nullptr);
auto upper_lvl_el = 0;
kax_file_cptr kax_file = kax_file_cptr(new kax_file_c(in));

kax_file->set_segment_end(*l0);

if (!l0->IsFiniteSize())
show_element(l0, 0, Y("Segment, size unknown"));
else
show_element(l0, 0, boost::format(Y("Segment, size %1%")) % l0->GetSize());

// Prevent reporting "first timecode after resync":
kax_file->set_timecode_scale(-1);

while ((l1 = kax_file->read_next_level1_element())) {
std::shared_ptr<EbmlElement> af_l1(l1);

if (Is<KaxInfo>(l1))
handle_info(es, upper_lvl_el, l1);

else if (Is<KaxTracks>(l1))
handle_tracks(es, upper_lvl_el, l1);

else if (Is<KaxSeekHead>(l1))
handle_seek_head(es, upper_lvl_el, l1);

else if (Is<KaxCluster>(l1)) {
show_element(l1, 1, Y("Cluster"));
if ((g_options.m_verbose == 0) && !g_options.m_show_summary)
return;
handle_cluster(es, upper_lvl_el, l1, file_size);

} else if (Is<KaxCues>(l1))
handle_cues(es, upper_lvl_el, l1);

// Weee! Attachments!
else if (Is<KaxAttachments>(l1))
handle_attachments(es, upper_lvl_el, l1);

else if (Is<KaxChapters>(l1))
handle_chapters(es, upper_lvl_el, l1);

// Let's handle some TAGS.
else if (Is<KaxTags>(l1))
handle_tags(es, upper_lvl_el, l1);

else if (!is_global(es, l1, 1))
show_unknown_element(l1, 1);

if (!in->setFilePointer2(l1->GetElementPosition() + kax_file->get_element_size(l1)))
break;
if (!in_parent(l0))
break;
} // while (l1)
}

void
display_track_info() {
if (!g_options.m_show_track_info)
Expand Down Expand Up @@ -1587,9 +1648,7 @@ display_track_info() {

bool
process_file(const std::string &file_name) {
int upper_lvl_el;
// Elements for different levels
EbmlElement *l0 = nullptr, *l1 = nullptr;

s_tc_scale = TIMECODE_SCALE;
s_tracks.clear();
Expand All @@ -1605,100 +1664,40 @@ process_file(const std::string &file_name) {
return false;
}

in->setFilePointer(0, seek_end);
uint64_t file_size = in->getFilePointer();
in->setFilePointer(0, seek_beginning);

try {
EbmlStream *es = new EbmlStream(*in);
auto es_ptr = std::make_shared<EbmlStream>(*in);
auto es = es_ptr.get();

// Find the EbmlHead element. Must be the first one.
l0 = es->FindNextID(EBML_INFO(EbmlHead), 0xFFFFFFFFL);
if (!l0 || !Is<EbmlHead>(l0)) {
auto l0 = ebml_element_cptr{ es->FindNextID(EBML_INFO(EbmlHead), 0xFFFFFFFFL) };
if (!l0 || !Is<EbmlHead>(*l0)) {
show_error(Y("No EBML head found."));
delete es;

return false;
}

handle_ebml_head(l0, in, es);
handle_ebml_head(l0.get(), in, es);
l0->SkipData(*es, EBML_CONTEXT(l0));
delete l0;

while (1) {
// NEXT element must be a segment
l0 = es->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFFFFFFFFFLL);
if (!l0) {
show_error(Y("No segment/level 0 element found."));
return false;
}

if (Is<KaxSegment>(l0)) {
if (!l0->IsFiniteSize())
show_element(l0, 0, Y("Segment, size unknown"));
else
show_element(l0, 0, boost::format(Y("Segment, size %1%")) % l0->GetSize());
l0 = ebml_element_cptr{ es->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFFFFFFFFFLL) };
if (!l0)
break;
}

show_element(l0, 0, boost::format(Y("Next level 0 element is not a segment but %1%")) % typeid(*l0).name());

l0->SkipData(*es, EBML_CONTEXT(l0));
delete l0;
}

kax_file_cptr kax_file = kax_file_cptr(new kax_file_c(in));

// Prevent reporting "first timecode after resync":
kax_file->set_timecode_scale(-1);

while ((l1 = kax_file->read_next_level1_element())) {
std::shared_ptr<EbmlElement> af_l1(l1);

if (Is<KaxInfo>(l1))
handle_info(es, upper_lvl_el, l1);

else if (Is<KaxTracks>(l1))
handle_tracks(es, upper_lvl_el, l1);

else if (Is<KaxSeekHead>(l1))
handle_seek_head(es, upper_lvl_el, l1);
if (!Is<KaxSegment>(*l0)) {
show_element(l0.get(), 0, Y("Unknown element"));
l0->SkipData(*es, EBML_CONTEXT(l0));

else if (Is<KaxCluster>(l1)) {
show_element(l1, 1, Y("Cluster"));
if ((g_options.m_verbose == 0) && !g_options.m_show_summary) {
delete l0;
delete es;

return true;
}
handle_cluster(es, upper_lvl_el, l1, file_size);

} else if (Is<KaxCues>(l1))
handle_cues(es, upper_lvl_el, l1);

// Weee! Attachments!
else if (Is<KaxAttachments>(l1))
handle_attachments(es, upper_lvl_el, l1);

else if (Is<KaxChapters>(l1))
handle_chapters(es, upper_lvl_el, l1);
continue;
}

// Let's handle some TAGS.
else if (Is<KaxTags>(l1))
handle_tags(es, upper_lvl_el, l1);
handle_segment(l0.get(), in, es);

else if (!is_global(es, l1, 1))
show_unknown_element(l1, 1);
l0->SkipData(*es, EBML_CONTEXT(l0));

if (!in->setFilePointer2(l1->GetElementPosition() + kax_file->get_element_size(l1)))
break;
if (!in_parent(l0))
if ((g_options.m_verbose == 0) && !g_options.m_show_summary)
break;
} // while (l1)

delete l0;
delete es;
}

if (!g_options.m_use_gui && g_options.m_show_track_info)
display_track_info();
Expand Down

0 comments on commit c035397

Please sign in to comment.