/*! * \brief Parses the "EditionEntry"-element specified when constructing the object. * * Fetches the chapters() but does not parse them. * * Clears all previous parsing results. */ void MatroskaEditionEntry::parse(Diagnostics &diag) { // clear previous values and status static const string context("parsing \"EditionEntry\"-element"); clear(); // iterate through children of "EditionEntry"-element EbmlElement *entryChild = m_editionEntryElement->firstChild(); while (entryChild) { entryChild->parse(diag); switch (entryChild->id()) { case MatroskaIds::EditionUID: m_id = entryChild->readUInteger(); break; case MatroskaIds::EditionFlagHidden: m_hidden = entryChild->readUInteger() == 1; break; case MatroskaIds::EditionFlagDefault: m_default = entryChild->readUInteger() == 1; break; case MatroskaIds::EditionFlagOrdered: m_ordered = entryChild->readUInteger() == 1; break; case MatroskaIds::ChapterAtom: m_chapters.emplace_back(make_unique<MatroskaChapter>(entryChild)); break; default: diag.emplace_back(DiagLevel::Warning, "\"EditionEntry\"-element contains unknown child element \"" % entryChild->idToString() + "\" which will be ingored.", context); } entryChild = entryChild->nextSibling(); } }
bool EbmlCrc32::CheckElementCRC32(EbmlElement &ElementToCRC) { MemIOCallback memoryBuffer; ElementToCRC.Render(memoryBuffer); return CheckCRC(m_crc_final, memoryBuffer.GetDataBuffer(), memoryBuffer.GetDataBufferSize()); };
void EbmlCrc32::AddElementCRC32(EbmlElement &ElementToCRC) { // Use a special IOCallback class that Render's to memory instead of to disk MemIOCallback memoryBuffer; ElementToCRC.Render(memoryBuffer, true, true); Update(memoryBuffer.GetDataBuffer(), memoryBuffer.GetDataBufferSize()); // Finalize(); };
ebml_master_cptr kax_analyzer_c::read_all(const EbmlCallbacks &callbacks) { reopen_file(); ebml_master_cptr master; EbmlStream es(*m_file); size_t i; for (i = 0; m_data.size() > i; ++i) { kax_analyzer_data_c &data = *m_data[i].get(); if (EBML_INFO_ID(callbacks) != data.m_id) continue; m_file->setFilePointer(data.m_pos); int upper_lvl_el = 0; EbmlElement *element = es.FindNextElement(EBML_CLASS_CONTEXT(KaxSegment), upper_lvl_el, 0xFFFFFFFFL, true); if (!element) continue; if (EbmlId(*element) != EBML_INFO_ID(callbacks)) { delete element; continue; } EbmlElement *l2 = nullptr; element->Read(*m_stream, EBML_INFO_CONTEXT(callbacks), upper_lvl_el, l2, true); if (!master) master = ebml_master_cptr(static_cast<EbmlMaster *>(element)); else { EbmlMaster *src = static_cast<EbmlMaster *>(element); while (src->ListSize() > 0) { master->PushElement(*(*src)[0]); src->Remove(0); } delete element; } } if (master && (master->ListSize() == 0)) master.reset(); return master; }
std::vector<std::string> EbmlMaster::FindAllMissingElements() { assert(Context.GetSize() != 0); std::vector<std::string> missingElements; for (size_t ChildElementNo = 0; ChildElementNo < ElementList.size(); ChildElementNo++) { EbmlElement *childElement = ElementList[ChildElementNo]; if (!childElement->ValueIsSet()) { std::string missingValue; missingValue = "The Child Element \""; missingValue.append(EBML_NAME(childElement)); missingValue.append("\" of EbmlMaster \""); missingValue.append(EBML_NAME(this)); missingValue.append("\", does not have a value set."); missingElements.push_back(missingValue); } if (childElement->IsMaster()) { EbmlMaster *childMaster = (EbmlMaster *)childElement; std::vector<std::string> childMissingElements = childMaster->FindAllMissingElements(); for (size_t s = 0; s < childMissingElements.size(); s++) missingElements.push_back(childMissingElements[s]); } } unsigned int EltIdx; for (EltIdx = 0; EltIdx < EBML_CTX_SIZE(Context); EltIdx++) { if (EBML_CTX_IDX(Context,EltIdx).IsMandatory()) { if (FindElt(EBML_CTX_IDX_INFO(Context,EltIdx)) == NULL) { std::string missingElement; missingElement = "Missing element \""; missingElement.append(EBML_INFO_NAME(EBML_CTX_IDX_INFO(Context,EltIdx))); missingElement.append("\" in EbmlMaster \""); missingElement.append(EBML_INFO_NAME(*EBML_CTX_MASTER(Context))); missingElement.append("\""); missingElements.push_back(missingElement); } } } return missingElements; }
uint64 EbmlVoid::Overwrite(const EbmlElement & EltToVoid, IOCallback & output, bool ComeBackAfterward, bool bWithDefault) { // EltToVoid.UpdateSize(bWithDefault); if (EltToVoid.GetElementPosition() == 0) { // this element has never been written return 0; } if (EltToVoid.GetSize() + EltToVoid.HeadSize() <2) { // the element can't be written here ! return 0; } uint64 CurrentPosition = output.getFilePointer(); output.setFilePointer(EltToVoid.GetElementPosition()); // compute the size of the voided data based on the original one SetSize(EltToVoid.GetSize() + EltToVoid.HeadSize() - 1); // 1 for the ID SetSize(GetSize() - CodedSizeLength(GetSize(), GetSizeLength(), IsFiniteSize())); // make sure we handle even the strange cases //uint32 A1 = GetSize() + HeadSize(); //uint32 A2 = EltToVoid.GetSize() + EltToVoid.HeadSize(); if (GetSize() + HeadSize() != EltToVoid.GetSize() + EltToVoid.HeadSize()) { SetSize(GetSize()-1); SetSizeLength(CodedSizeLength(GetSize(), GetSizeLength(), IsFiniteSize()) + 1); } if (GetSize() != 0) { RenderHead(output, false, bWithDefault); // the rest of the data is not rewritten } if (ComeBackAfterward) { output.setFilePointer(CurrentPosition); } return EltToVoid.GetSize() + EltToVoid.HeadSize(); }
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(); }
void matroska_segment_c::LoadTags( KaxTags *tags ) { /* Master elements */ EbmlParser eparser = EbmlParser( &es, tags, &sys.demuxer, true ); EbmlElement *el; while( ( el = eparser.Get() ) != NULL ) { if( MKV_IS_ID( el, KaxTag ) ) { Tag tag; msg_Dbg( &sys.demuxer, "+ Tag" ); eparser.Down(); int target_type = 50; while( ( el = eparser.Get() ) != NULL ) { if( MKV_IS_ID( el, KaxTagTargets ) ) { msg_Dbg( &sys.demuxer, "| + Targets" ); eparser.Down(); while( ( el = eparser.Get() ) != NULL ) { try { if( unlikely( !el->ValidateSize() ) ) { msg_Err( &sys.demuxer, "Invalid size while reading tag"); break; } if( MKV_CHECKED_PTR_DECL ( ktttv_ptr, KaxTagTargetTypeValue, el ) ) { ktttv_ptr->ReadData( es.I_O() ); msg_Dbg( &sys.demuxer, "| | + TargetTypeValue: %u", uint32(*ktttv_ptr)); target_type = static_cast<uint32>( *ktttv_ptr ); } else if( MKV_CHECKED_PTR_DECL ( kttu_ptr, KaxTagTrackUID, el ) ) { tag.i_tag_type = TRACK_UID; kttu_ptr->ReadData( es.I_O() ); tag.i_uid = static_cast<uint64>( *kttu_ptr ); msg_Dbg( &sys.demuxer, "| | + TrackUID: %" PRIu64, tag.i_uid); } else if( MKV_CHECKED_PTR_DECL ( kteu_ptr, KaxTagEditionUID, el ) ) { tag.i_tag_type = EDITION_UID; kteu_ptr->ReadData( es.I_O() ); tag.i_uid = static_cast<uint64>( *kteu_ptr ); msg_Dbg( &sys.demuxer, "| | + EditionUID: %" PRIu64, tag.i_uid); } else if( MKV_CHECKED_PTR_DECL ( ktcu_ptr, KaxTagChapterUID, el ) ) { tag.i_tag_type = CHAPTER_UID; ktcu_ptr->ReadData( es.I_O() ); tag.i_uid = static_cast<uint64>( *ktcu_ptr ); msg_Dbg( &sys.demuxer, "| | + ChapterUID: %" PRIu64, tag.i_uid); } else if( MKV_CHECKED_PTR_DECL ( ktau_ptr, KaxTagAttachmentUID, el ) ) { tag.i_tag_type = ATTACHMENT_UID; ktau_ptr->ReadData( es.I_O() ); tag.i_uid = static_cast<uint64>( *ktau_ptr ); msg_Dbg( &sys.demuxer, "| | + AttachmentUID: %" PRIu64, tag.i_uid); } else { msg_Dbg( &sys.demuxer, "| | + LoadTag Unknown (%s)", typeid( *el ).name() ); } } catch(...) { msg_Err( &sys.demuxer, "Error while reading tag"); break; } } eparser.Up(); } else if( MKV_CHECKED_PTR_DECL ( kts_ptr, KaxTagSimple, el ) ) { SimpleTag simple; if (ParseSimpleTags(&simple, kts_ptr, target_type )) { tag.simple_tags.push_back( simple ); } } else { msg_Dbg( &sys.demuxer, "| + LoadTag Unknown (%s)", typeid( *el ).name() ); } } eparser.Up(); this->tags.push_back(tag); } else { msg_Dbg( &sys.demuxer, "+ Unknown (%s)", typeid( *el ).name() ); } } msg_Dbg( &sys.demuxer, "loading tags done." ); }
bool matroska_segment_c::ParseSimpleTags( SimpleTag* pout_simple, KaxTagSimple *tag, int target_type ) { EbmlParser eparser ( &es, tag, &sys.demuxer, var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) ); EbmlElement *el; size_t max_size = tag->GetSize(); size_t size = 0; if( !sys.meta ) sys.meta = vlc_meta_New(); msg_Dbg( &sys.demuxer, "| + Simple Tag "); try { while( ( el = eparser.Get() ) != NULL && size < max_size) { if( unlikely( !el->ValidateSize() ) ) { msg_Err( &sys.demuxer, "Error %s too big ignoring the tag", typeid(*el).name() ); delete ep; return false; } if( MKV_CHECKED_PTR_DECL ( ktn_ptr, KaxTagName, el ) ) { ktn_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA ); pout_simple->tag_name = UTFstring( *ktn_ptr ).GetUTF8().c_str(); } else if( MKV_CHECKED_PTR_DECL ( kts_ptr, KaxTagString, el ) ) { kts_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA ); pout_simple->value = UTFstring( *kts_ptr ).GetUTF8().c_str(); } else if( MKV_CHECKED_PTR_DECL ( ktl_ptr, KaxTagLangue, el ) ) { ktl_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA ); pout_simple->lang = *ktl_ptr; } else if( MKV_CHECKED_PTR_DECL ( ktd_ptr, KaxTagDefault, el ) ) { VLC_UNUSED(ktd_ptr); // TODO: we do not care about this value, but maybe we should? } /*Tags can be nested*/ else if( MKV_CHECKED_PTR_DECL ( kts_ptr, KaxTagSimple, el) ) { SimpleTag st; // ParseSimpleTags will write to this variable // the SimpleTag is valid if ParseSimpleTags returns `true` if (ParseSimpleTags( &st, kts_ptr, target_type )) { pout_simple->sub_tags.push_back( st ); } } /*TODO Handle binary tags*/ size += el->HeadSize() + el->GetSize(); } } catch(...) { msg_Err( &sys.demuxer, "Error while reading Tag "); delete ep; return false; } if( pout_simple->tag_name.empty() ) { msg_Warn( &sys.demuxer, "Invalid MKV SimpleTag found."); return false; } for( int i = 0; metadata_map[i].key; i++ ) { if( pout_simple->tag_name == metadata_map[i].key && (metadata_map[i].target_type == 0 || target_type == metadata_map[i].target_type ) ) { vlc_meta_Set( sys.meta, metadata_map[i].type, pout_simple->value.c_str () ); msg_Dbg( &sys.demuxer, "| | + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ()); goto done; } } msg_Dbg( &sys.demuxer, "| | + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ()); vlc_meta_AddExtra( sys.meta, pout_simple->tag_name.c_str (), pout_simple->value.c_str ()); done: return true; }
/***************************************************************************** * Tools * ***************************************************************************** * * LoadCues : load the cues element and update index * * LoadTags : load ... the tags element * * InformationCreate : create all information, load tags if present *****************************************************************************/ void matroska_segment_c::LoadCues( KaxCues *cues ) { EbmlElement *el; if( b_cues ) { msg_Err( &sys.demuxer, "There can be only 1 Cues per section." ); return; } EbmlParser eparser (&es, cues, &sys.demuxer, var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) ); while( ( el = eparser.Get() ) != NULL ) { if( MKV_IS_ID( el, KaxCuePoint ) ) { uint64_t cue_position = -1; mtime_t cue_mk_time = -1; unsigned int track_id = 0; bool b_invalid_cue = false; eparser.Down(); while( ( el = eparser.Get() ) != NULL ) { if ( MKV_CHECKED_PTR_DECL( kct_ptr, KaxCueTime, el ) ) { try { if( unlikely( !kct_ptr->ValidateSize() ) ) { msg_Err( &sys.demuxer, "CueTime size too big"); b_invalid_cue = true; break; } kct_ptr->ReadData( es.I_O() ); } catch(...) { msg_Err( &sys.demuxer, "Error while reading CueTime" ); b_invalid_cue = true; break; } cue_mk_time = static_cast<uint64>( *kct_ptr ) * i_timescale / INT64_C(1000); } else if( MKV_IS_ID( el, KaxCueTrackPositions ) ) { eparser.Down(); try { while( ( el = eparser.Get() ) != NULL ) { if( unlikely( !el->ValidateSize() ) ) { eparser.Up(); msg_Err( &sys.demuxer, "Error %s too big, aborting", typeid(*el).name() ); b_invalid_cue = true; break; } if( MKV_CHECKED_PTR_DECL ( kct_ptr, KaxCueTrack, el ) ) { kct_ptr->ReadData( es.I_O() ); track_id = static_cast<uint16>( *kct_ptr ); } else if( MKV_CHECKED_PTR_DECL ( kccp_ptr, KaxCueClusterPosition, el ) ) { kccp_ptr->ReadData( es.I_O() ); cue_position = segment->GetGlobalPosition( static_cast<uint64>( *kccp_ptr ) ); _seeker.add_cluster_position( cue_position ); } else if( MKV_CHECKED_PTR_DECL ( kcbn_ptr, KaxCueBlockNumber, el ) ) { VLC_UNUSED( kcbn_ptr ); } #if LIBMATROSKA_VERSION >= 0x010401 else if( MKV_IS_ID( el, KaxCueRelativePosition ) ) { b_invalid_cue = true; // since we do not support this type of cue: IGNORE } else if( MKV_IS_ID( el, KaxCueBlockNumber ) ) { b_invalid_cue = true; // since we do not support this type of cue: IGNORE } else if( MKV_IS_ID( el, KaxCueReference ) ) { b_invalid_cue = true; // since we do not support this type of cue: IGNORE } else if( MKV_IS_ID( el, KaxCueDuration ) ) { /* For future use */ } #endif else { msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() ); } } } catch(...) { eparser.Up(); msg_Err( &sys.demuxer, "Error while reading %s", typeid(*el).name() ); b_invalid_cue = true; break; } eparser.Up(); } else { msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() ); } } eparser.Up(); if( track_id != 0 && cue_mk_time != -1 && cue_position != static_cast<uint64_t>( -1 ) ) { if( tracks.find( track_id ) != tracks.end() ) { int level = SegmentSeeker::Seekpoint::DISABLED; if( ! b_invalid_cue ) { level = SegmentSeeker::Seekpoint::QUESTIONABLE; // TODO: var_InheritBool( ..., "mkv-trust-cues" ); } _seeker.add_seekpoint( track_id, level, cue_position, cue_mk_time ); } else msg_Warn( &sys.demuxer, "Found cue with invalid track id = %u", track_id ); } } else { msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() ); } } b_cues = true; msg_Dbg( &sys.demuxer, "| - loading cues done." ); }
uint64 KaxSegment::GetRelativePosition(const EbmlElement & Elt) const { return GetRelativePosition(Elt.GetElementPosition()); }
/*! * \brief Parses field information from the specified EbmlElement. * * The specified atom should be a simple tag element. These elements * represents the fields of a MatroskaTag. * * \throws Throws std::ios_base::failure when an IO error occurs. * \throws Throws TagParser::Failure or a derived exception when a parsing * error occurs. */ void MatroskaTagField::reparse(EbmlElement &simpleTagElement, Diagnostics &diag, bool parseNestedFields) { string context("parsing Matroska tag field"); simpleTagElement.parse(diag); bool tagDefaultFound = false; for (EbmlElement *child = simpleTagElement.firstChild(); child; child = child->nextSibling()) { try { child->parse(diag); } catch (const Failure &) { diag.emplace_back(DiagLevel::Critical, "Unable to parse children of \"SimpleTag\"-element.", context); break; } switch (child->id()) { case MatroskaIds::TagName: if (id().empty()) { setId(child->readString()); context = "parsing Matroska tag field " + id(); } else { diag.emplace_back(DiagLevel::Warning, "\"SimpleTag\"-element contains multiple \"TagName\"-elements. Surplus TagName elements will be ignored.", context); } break; case MatroskaIds::TagString: case MatroskaIds::TagBinary: if (value().isEmpty()) { unique_ptr<char[]> buffer = make_unique<char[]>(child->dataSize()); child->stream().seekg(static_cast<streamoff>(child->dataOffset())); child->stream().read(buffer.get(), static_cast<streamoff>(child->dataSize())); switch (child->id()) { case MatroskaIds::TagString: value().assignData(move(buffer), child->dataSize(), TagDataType::Text, TagTextEncoding::Utf8); break; case MatroskaIds::TagBinary: value().assignData(move(buffer), child->dataSize(), TagDataType::Undefined); break; } } else { diag.emplace_back(DiagLevel::Warning, "\"SimpleTag\"-element contains multiple \"TagString\"/\"TagBinary\"-elements. Surplus \"TagName\"/\"TagBinary\"-elements will " "be ignored.", context); } break; case MatroskaIds::TagLanguage: if (value().language().empty() || value().language() == "und") { string lng = child->readString(); if (lng != "und") { value().setLanguage(lng); } } else { diag.emplace_back(DiagLevel::Warning, "\"SimpleTag\"-element contains multiple \"TagLanguage\"-elements. Surplus \"TagLanguage\"-elements will be ignored.", context); } break; case MatroskaIds::TagDefault: if (!tagDefaultFound) { setDefault(child->readUInteger() > 0); tagDefaultFound = true; } else { diag.emplace_back(DiagLevel::Warning, "\"SimpleTag\"-element contains multiple \"TagDefault\" elements. Surplus \"TagDefault\"-elements will be ignored.", context); } break; case MatroskaIds::SimpleTag: if (parseNestedFields) { nestedFields().emplace_back(); nestedFields().back().reparse(*child, diag, true); } else { diag.emplace_back(DiagLevel::Warning, "Nested fields are currently not supported. Nested tags can not be displayed and will be discarded when rewriting the file.", context); } break; case EbmlIds::Crc32: case EbmlIds::Void: break; default: diag.emplace_back(DiagLevel::Warning, argsToString( "\"SimpleTag\"-element contains unknown element ", child->idToString(), " at ", child->startOffset(), ". It will be ignored."), context); } } }
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(); }
/*! \brief Method to help reading a Master element and all subsequent children quickly \todo add an option to discard even unknown elements \todo handle when a mandatory element is not found */ void EbmlMaster::Read(EbmlStream & inDataStream, const EbmlSemanticContext & sContext, int & UpperEltFound, EbmlElement * & FoundElt, bool AllowDummyElt, ScopeMode ReadFully) { if (ReadFully != SCOPE_NO_DATA) { EbmlElement * ElementLevelA; // remove all existing elements, including the mandatory ones... size_t Index; for (Index=0; Index<ElementList.size(); Index++) { if (!(*ElementList[Index]).IsLocked()) { delete ElementList[Index]; } } ElementList.clear(); uint64 MaxSizeToRead; if (IsFiniteSize()) MaxSizeToRead = GetSize(); else MaxSizeToRead = 0x7FFFFFFF; // read blocks and discard the ones we don't care about if (MaxSizeToRead > 0) { inDataStream.I_O().setFilePointer(GetSizePosition() + GetSizeLength(), seek_beginning); ElementLevelA = inDataStream.FindNextElement(sContext, UpperEltFound, MaxSizeToRead, AllowDummyElt); while (ElementLevelA != NULL && UpperEltFound <= 0 && MaxSizeToRead > 0) { if (IsFiniteSize()) MaxSizeToRead = GetEndPosition() - ElementLevelA->GetEndPosition(); // even if it's the default value if (!AllowDummyElt && ElementLevelA->IsDummy()) { ElementLevelA->SkipData(inDataStream, sContext); delete ElementLevelA; // forget this unknown element } else { // more logical to do it afterward ElementList.push_back(ElementLevelA); ElementLevelA->Read(inDataStream, EBML_CONTEXT(ElementLevelA), UpperEltFound, FoundElt, AllowDummyElt, ReadFully); // just in case ElementLevelA->SkipData(inDataStream, EBML_CONTEXT(ElementLevelA)); } if (UpperEltFound > 0) { UpperEltFound--; if (UpperEltFound > 0 || MaxSizeToRead <= 0) goto processCrc; ElementLevelA = FoundElt; continue; } if (UpperEltFound < 0) { UpperEltFound++; if (UpperEltFound < 0) goto processCrc; } if (MaxSizeToRead <= 0) goto processCrc;// this level is finished ElementLevelA = inDataStream.FindNextElement(sContext, UpperEltFound, MaxSizeToRead, AllowDummyElt); } if (UpperEltFound > 0) { FoundElt = ElementLevelA; } } processCrc: EBML_MASTER_ITERATOR Itr, CrcItr; for (Itr = ElementList.begin(); Itr != ElementList.end();) { if ((EbmlId)(*(*Itr)) == EBML_ID(EbmlCrc32)) { bChecksumUsed = true; // remove the element Checksum = *(static_cast<EbmlCrc32*>(*Itr)); CrcItr = Itr; break; } ++Itr; } if (bChecksumUsed) { delete *CrcItr; Remove(CrcItr); } SetValueIsSet(); } }