static vint_c read_id(int64_t end_pos) { try { int64_t pos = g_in->getFilePointer(); int mask = 0x80; int id_len = 1; if (pos >= end_pos) throw id_error_c(id_error_c::end_of_scope); unsigned char first_byte = g_in->read_uint8(); while (0 != mask) { if (0 != (first_byte & mask)) break; mask >>= 1; id_len++; } if (0 == mask) throw id_error_c(id_error_c::first_byte_is_zero); if (4 < id_len) throw id_error_c(id_error_c::longer_than_four_bytes); if ((pos + id_len) > end_pos) throw id_error_c(id_error_c::end_of_scope); uint32_t id = first_byte; int i; for (i = 1; i < id_len; ++i) { id <<= 8; id |= g_in->read_uint8(); } return vint_c(id, id_len); } catch (mtx::exception &error) { throw id_error_c(id_error_c::end_of_file); } }
static vint_c read_size(int64_t end_pos) { try { int64_t pos = g_in->getFilePointer(); int mask = 0x80; int size_len = 1; if (pos >= end_pos) throw size_error_c(size_error_c::end_of_scope); unsigned char first_byte = g_in->read_uint8(); while (0 != mask) { if (0 != (first_byte & mask)) break; mask >>= 1; size_len++; } if ((pos + size_len) > end_pos) throw size_error_c(size_error_c::end_of_scope); int64_t size = first_byte & ~mask; int i; for (i = 1; i < size_len; ++i) { size <<= 8; size |= g_in->read_uint8(); } return vint_c(size, size_len); } catch (mtx::exception &error) { throw size_error_c(size_error_c::end_of_file); } }
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(); uint32_t actual_id = m_in->read_uint32_be(); int64_t start_time = mtx::sys::get_current_time_millis(); bool is_cluster_id = !wanted_id || (EBML_ID_VALUE(EBML_ID(KaxCluster)) == wanted_id); // 0 means: any level 1 element will do mxinfo(boost::format(Y("%1%: Error in the Matroska file structure at position %2%. Resyncing to the next level 1 element.\n")) % m_in->get_file_name() % m_resync_start_pos); if (is_cluster_id && (-1 != m_last_timecode)) { mxinfo(boost::format(Y("The last timecode processed before the error was encountered was %1%.\n")) % format_timecode(m_last_timecode)); m_last_timecode = -1; } if (m_debug_resync) mxinfo(boost::format("kax_file::resync_to_level1_element(): starting at %1% potential ID %|2$08x|\n") % m_resync_start_pos % actual_id); while (m_in->getFilePointer() < m_file_size) { int64_t now = mtx::sys::get_current_time_millis(); if ((now - start_time) >= 10000) { mxinfo(boost::format("Still resyncing at position %1%.\n") % m_in->getFilePointer()); start_time = now; } actual_id = (actual_id << 8) | m_in->read_uint8(); if ( ((0 != wanted_id) && (wanted_id != actual_id)) || ((0 == wanted_id) && !is_level1_element_id(vint_c(actual_id, 4)))) continue; uint64_t current_start_pos = m_in->getFilePointer() - 4; uint64_t element_pos = current_start_pos; unsigned int num_headers = 1; bool valid_unknown_size = false; if (m_debug_resync) mxinfo(boost::format("kax_file::resync_to_level1_element(): byte-for-byte search, found level 1 ID %|2$x| at %1%\n") % current_start_pos % actual_id); try { unsigned int idx; for (idx = 0; 3 > idx; ++idx) { vint_c length = vint_c::read(m_in); if (m_debug_resync) mxinfo(boost::format("kax_file::resync_to_level1_element(): read ebml length %1%/%2% valid? %3% unknown? %4%\n") % length.m_value % length.m_coded_size % length.is_valid() % length.is_unknown()); if (length.is_unknown()) { valid_unknown_size = true; break; } if ( !length.is_valid() || ((element_pos + length.m_value + length.m_coded_size + 2 * 4) >= m_file_size) || !m_in->setFilePointer2(element_pos + 4 + length.m_value + length.m_coded_size, seek_beginning)) break; element_pos = m_in->getFilePointer(); uint32_t next_id = m_in->read_uint32_be(); if (m_debug_resync) mxinfo(boost::format("kax_file::resync_to_level1_element(): next ID is %|1$x| at %2%\n") % next_id % element_pos); if ( ((0 != wanted_id) && (wanted_id != next_id)) || ((0 == wanted_id) && !is_level1_element_id(vint_c(next_id, 4)))) break; ++num_headers; } } catch (...) { } if ((4 == num_headers) || valid_unknown_size) { mxinfo(boost::format(Y("Resyncing successful at position %1%.\n")) % current_start_pos); m_in->setFilePointer(current_start_pos, seek_beginning); return read_next_level1_element(wanted_id, is_cluster_id); } m_in->setFilePointer(current_start_pos + 4, seek_beginning); } mxinfo(Y("Resync failed: no valid Matroska level 1 element found.\n")); return nullptr; }