/** \brief Merges consecutive EbmlVoid elements into a single one Iterates over the level 1 elements in the m_file and merges consecutive EbmlVoid elements into a single one which covers the same space as the smaller ones combined. Void elements at the end of the m_file are removed as well. */ void kax_analyzer_c::merge_void_elements() { size_t start_idx = 0; while (m_data.size() > start_idx) { // We only have to do work on EbmlVoid elements. Skip the others. if (!Is<EbmlVoid>(m_data[start_idx]->m_id)) { ++start_idx; continue; } // Found an EbmlVoid element. See how many consecutive EbmlVoid elements // there are at this position and calculate the combined size. size_t end_idx = start_idx + 1; size_t new_size = m_data[start_idx]->m_size; while ((m_data.size() > end_idx) && Is<EbmlVoid>(m_data[end_idx]->m_id)) { new_size += m_data[end_idx]->m_size; ++end_idx; } // Is this only a single EbmlVoid element? If yes continue. if (end_idx == (start_idx + 1)) { start_idx += 2; continue; } // Write the new EbmlVoid element to the m_file. m_file->setFilePointer(m_data[start_idx]->m_pos); EbmlVoid evoid; evoid.SetSize(new_size); evoid.UpdateSize(); evoid.SetSize(new_size - evoid.HeadSize()); evoid.Render(*m_file); // Update the internal records to reflect the changes. m_data[start_idx]->m_size = new_size; m_data.erase(m_data.begin() + start_idx + 1, m_data.begin() + end_idx); start_idx += 2; } // See how many void elements there are at the end of the m_file. start_idx = m_data.size(); while ((0 < start_idx) && Is<EbmlVoid>(m_data[start_idx - 1]->m_id)) --start_idx; // If there are none then we're done. if (m_data.size() <= start_idx) return; // Truncate the m_file after the last non-void element and update the m_segment size. m_file->truncate(m_data[start_idx]->m_pos); adjust_segment_size(); }
uint64 EbmlVoid::ReplaceWith(EbmlElement & EltToReplaceWith, IOCallback & output, bool ComeBackAfterward, bool bWithDefault) { EltToReplaceWith.UpdateSize(bWithDefault); if (HeadSize() + GetSize() < EltToReplaceWith.GetSize() + EltToReplaceWith.HeadSize()) { // the element can't be written here ! return INVALID_FILEPOS_T; } if (HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() == 1) { // there is not enough space to put a filling element return INVALID_FILEPOS_T; } uint64 CurrentPosition = output.getFilePointer(); output.setFilePointer(GetElementPosition()); EltToReplaceWith.Render(output, bWithDefault); if (HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() > 1) { // fill the rest with another void element EbmlVoid aTmp; aTmp.SetSize_(HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() - 1); // 1 is the length of the Void ID int HeadBefore = aTmp.HeadSize(); aTmp.SetSize_(aTmp.GetSize() - CodedSizeLength(aTmp.GetSize(), aTmp.GetSizeLength(), aTmp.IsFiniteSize())); int HeadAfter = aTmp.HeadSize(); if (HeadBefore != HeadAfter) { aTmp.SetSizeLength(CodedSizeLength(aTmp.GetSize(), aTmp.GetSizeLength(), aTmp.IsFiniteSize()) - (HeadAfter - HeadBefore)); } aTmp.RenderHead(output, false, bWithDefault); // the rest of the data is not rewritten } if (ComeBackAfterward) { output.setFilePointer(CurrentPosition); } return GetSize() + HeadSize(); }