Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/demux/mkv/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 11 kB image not shown  

Quelle  Ebml_parser.cpp   Sprache: C

 


/*****************************************************************************
 * EbmlParser for the matroska demuxer
 *****************************************************************************
 * Copyright (C) 2003-2004 VLC authors and VideoLAN
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Steve Lhomme <steve.lhomme@free.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#include "Ebml_parser.hpp"
#include "stream_io_callback.hpp"

namespace mkv {

/*****************************************************************************
 * Ebml Stream parser
 *****************************************************************************/

EbmlParser::EbmlParser( matroska_iostream_c *es, EbmlElement *el_start, demux_t *p_demux ) :
    p_demux( p_demux ),
    m_es( es ),
    mi_level( 1 ),
    mi_user_level( 1 ),
    mb_keep( false ),
    mb_dummy( var_InheritBool( p_demux, "mkv-use-dummy" ) )
{
    memset( m_el, 0, sizeof( *m_el ) * M_EL_MAXSIZE);
    m_el[0] = el_start;
}

EbmlParser::~EbmlParser( void )
{
    if( !mi_level )
    {
        assert( !mb_keep );
        delete m_el[1];
        return;
    }

    for( size_t i = 1; i <= mi_level; i++ )
    {
        if( !mb_keep )
        {
            delete m_el[i];
        }
        mb_keep = false;
    }
}

void EbmlParser::reconstruct( matroska_iostream_c* es, EbmlElement* el_start, demux_t* p_demux )
{
    this->~EbmlParser();

    new( static_cast<void*>( this ) ) EbmlParser( es, el_start, p_demux );
}

void EbmlParser::Up( void )
{
    if( mi_user_level == mi_level && m_el[mi_level] )
    {
        msg_Warn( p_demux, "MKV/Ebml Parser: Up cannot escape itself" );
    }

    assert(mi_user_level != 0);
    mi_user_level--;
}

void EbmlParser::Down( void )
{
    assert(m_el[mi_level] != nullptr);
    mi_user_level++;
    mi_level++;
}

void EbmlParser::Keep( void )
{
    mb_keep = true;
}

void EbmlParser::Unkeep()
{
    mb_keep = false;
}

int EbmlParser::GetLevel( void ) const
{
    return mi_user_level;
}

void EbmlParser::Reset( demux_t *p_demux )
{
    while ( mi_level > 0)
    {
        delete m_el[mi_level];
        m_el[mi_level] = NULL;
        mi_level--;
    }
    this->p_demux = p_demux;
    mi_user_level = mi_level = 1;
    return_previous_parent = false;
    // a little faster and cleaner
    m_es->I_O().setFilePointer( static_cast<EbmlMaster*>(m_el[0])->GetDataStart() );
}


static const EbmlSemanticContext & GetEbmlNoGlobal_Context();
static const EbmlSemanticContext EbmlNoGlobal_Context = EbmlSemanticContext(0, NULL, NULL, *GetEbmlNoGlobal_Context, NULL);
static const EbmlSemanticContext & GetEbmlNoGlobal_Context()
{
  return EbmlNoGlobal_Context;
}

// the Segment Context should not allow Void or CRC32 elements to avoid lookup false alarm
DEFINE_START_SEMANTIC(KaxSegmentVLC)
DEFINE_SEMANTIC_ITEM(true, true, EbmlHead)
DEFINE_SEMANTIC_ITEM(false, false, KaxSegment)
DEFINE_END_SEMANTIC(KaxSegmentVLC)

DEFINE_xxx_CONTEXT(KaxSegmentVLC,GetEbmlNoGlobal_Context)


EbmlElement *EbmlParser::Get( bool allow_overshoot )
{
    int i_ulev = 0;
    int n_call = 0;
    EbmlElement *p_prev = NULL;
    bool do_read = true;

    if( mi_user_level != mi_level )
    {
        return NULL;
    }
    if( return_previous_parent )
    {
        EbmlElement *ret = m_el[mi_level];
        return_previous_parent = false;

        if( mi_level > 0 && m_el[mi_level-1]->IsFiniteSize() )
        {
            if( ret->IsFiniteSize() &&
                ret->GetEndPosition() > m_el[mi_level-1]->GetEndPosition() )
            {
                msg_Err( p_demux, "EBML element at %" PRIu64 " extends beyond parent boundary (%" PRIu64 " beyond %" PRIu64 ")",
                         ret->GetElementPosition(), ret->GetEndPosition(), m_el[mi_level-1]->GetEndPosition() );
                delete ret;
                m_el[mi_level] = NULL;
                return NULL;
            }
            if( !ret->IsFiniteSize() )
            {
                msg_Dbg( p_demux, "Infinite EBML element %s at %" PRIu64 " inside finite parent",
                         EBML_NAME(ret), ret->GetElementPosition() );
            }
        }
        return ret;
    }

next:
    p_prev = m_el[mi_level];
    if( p_prev && p_prev->IsFiniteSize() )
        p_prev->SkipData( *m_es, EBML_CONTEXT(p_prev) );

    uint64_t i_max_read;
    if (mi_level == 0)
        i_max_read = UINT64_MAX;
    else if (!m_el[mi_level-1]->IsFiniteSize())
        i_max_read = UINT64_MAX;
    else if (!p_prev)
    {
        i_max_read = m_el[mi_level-1]->GetSize();
        if (i_max_read == 0)
        {
            /* check if the parent still has data to read */
            if ( mi_level > 1 && m_el[mi_level-2]->IsFiniteSize() &&
                 m_el[mi_level-1]->GetEndPosition() < m_el[mi_level-2]->GetEndPosition() )
            {
                uint64_t top = m_el[mi_level-2]->GetEndPosition();
                uint64_t bom = m_el[mi_level-1]->GetEndPosition();
                i_max_read = top - bom;
            }
        }
    }
    else {
        size_t size_lvl = mi_level;
        while ( size_lvl && m_el[size_lvl-1]->IsFiniteSize() && m_el[size_lvl]->IsFiniteSize() &&
                m_el[size_lvl-1]->GetEndPosition() == m_el[size_lvl]->GetEndPosition() )
            size_lvl--;
        if (size_lvl == 0 && !allow_overshoot)
        {
            i_ulev = mi_level; // trick to go all the way up
            m_el[mi_level] = NULL;
            do_read = false;
        }
        else if (size_lvl == 0 || !m_el[size_lvl-1]->IsFiniteSize() || !m_el[size_lvl]->IsFiniteSize() )
            i_max_read = UINT64_MAX;
        else {
            uint64_t top = m_el[size_lvl-1]->GetEndPosition();
            uint64_t bom = m_el[mi_level]->GetEndPosition();
            i_max_read = top - bom;
        }
    }

    if (do_read)
    {
        // avoid leaking previous element at the level we're reading
        if(m_el[mi_level] != nullptr && !mb_keep)
        {
            assert(m_el[mi_level] == p_prev);
            delete m_el[mi_level];
            p_prev = nullptr;
        }

        // If the parent is a segment, use the segment context when creating children
        // (to prolong their lifetime), otherwise just continue as normal
        EbmlSemanticContext e_context =
                (mi_level == 0 || EBML_CTX_MASTER( EBML_CONTEXT(m_el[mi_level - 1]) ) == EBML_CTX_MASTER( Context_KaxSegmentVLC ))
                ? Context_KaxSegmentVLC
                : EBML_CONTEXT(m_el[mi_level - 1]);

        /* Ignore unknown level 0 or 1 elements */
        m_el[mi_level] = unlikely(!i_max_read) ? NULL :
                         m_es->FindNextElement( e_context,
                                                i_ulev, i_max_read,
                                                (  mb_dummy | (mi_level > 1) ), 1 );

        if( m_el[mi_level] == NULL )
        {
            if ( i_max_read != UINT64_MAX )
            {
                msg_Dbg(p_demux, "found nothing, go up");
                i_ulev = 1;
            }
        }
    }

    if( i_ulev > 0 )
    {
        if( p_prev )
        {
            if( !mb_keep )
            {
                delete p_prev;
                p_prev = NULL;
            }
            mb_keep = false;
        }
        while( i_ulev > 0 )
        {
            if( mi_level == 1 )
            {
                mi_level = 0;
                return NULL;
            }

            delete m_el[mi_level - 1];
            m_el[mi_level -1] = m_el[mi_level];
            m_el[mi_level] = NULL;
            return_previous_parent = m_el[mi_level - 1] != NULL;

            mi_level--;
            i_ulev--;
        }
        return NULL;
    }
    if( m_el[mi_level] == NULL )
    {
        msg_Dbg( p_demux,"MKV/Ebml Parser: m_el[mi_level] == NULL" );
        /* go back to the end of the parent */
        if( p_prev && p_prev->IsFiniteSize() )
            p_prev->SkipData( *m_es, EBML_CONTEXT(p_prev) );
    }
    else if( m_el[mi_level]->IsDummy() && !mb_dummy )
    {
        bool b_bad_position = false;
        /* We got a dummy element but don't want those...
         * perform a sanity check */

        if( !mi_level )
        {
            msg_Err(p_demux, "Got invalid lvl 0 element... Aborting");
            return NULL;
        }

        if( mi_level > 1 &&
            p_prev && p_prev->IsFiniteSize() &&
            p_prev->GetEndPosition() != m_el[mi_level]->GetElementPosition() )
        {
            msg_Err( p_demux, "Dummy Element at unexpected position (%" PRIu64 " instead of %" PRIu64 ")... corrupted file?",
                        m_el[mi_level]->GetElementPosition(), p_prev->GetEndPosition() );
            b_bad_position = true;
        }

        if( p_prev )
        {
            if( !mb_keep )
            {
                delete p_prev;
                p_prev = NULL;
            }
            mb_keep = false;
        }

        if( n_call < M_EL_MAXSIZE && !b_bad_position && m_el[mi_level]->IsFiniteSize() &&
            ( !m_el[mi_level-1]->IsFiniteSize() ||
              m_el[mi_level]->GetEndPosition() <= m_el[mi_level-1]->GetEndPosition() ) )
        {
            /* The element fits inside its upper element */
            msg_Warn( p_demux, "Dummy element found %" PRIu64 "... skipping it",
                      m_el[mi_level]->GetElementPosition() );
            n_call++;
        }
        else
        {
            /* Too large, misplaced or M_EL_MAXSIZE successive dummy elements */
            msg_Err( p_demux,
                     "Dummy element too large or misplaced at %" PRIu64 "... skipping to next upper element",
                     m_el[mi_level]->GetElementPosition() );

            if( m_el[mi_level]->IsFiniteSize() && m_el[mi_level-1]->IsFiniteSize() &&
                m_el[mi_level]->GetElementPosition() >= m_el[mi_level-1]->GetEndPosition() )
            {
                msg_Err(p_demux, "This element is outside its known parent... upping level");
                delete m_el[mi_level - 1];
                m_el[mi_level -1] = m_el[mi_level];
                m_el[mi_level] = NULL;
                return_previous_parent = m_el[mi_level - 1] != NULL;

                mi_level--;
                return NULL;
            }
        }

        goto next;
    }

    if( p_prev )
    {
        if( !mb_keep )
        {
            delete p_prev;
        }
        mb_keep = false;
    }
    return m_el[mi_level];
}

bool EbmlParser::IsTopPresent( EbmlElement *el ) const
{
    for( size_t i = 0; i < mi_level; i++ )
    {
        if( m_el[i] && m_el[i] == el )
            return true;
    }
    return false;
}

} // namespace

Messung
CHZG
85949992

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.