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

Quelle  asx.c   Sprache: C

 

/*****************************************************************************
 * asx.c : ASX playlist format import
 *****************************************************************************
 * Copyright (C) 2005-2013 VLC authors and VideoLAN
 *
 * Authors: Derk-Jan Hartman <hartman at videolan dot org>
 *
 * 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.
 *****************************************************************************/


/* See also:
 * http://msdn.microsoft.com/en-us/library/windows/desktop/dd564668.aspx
 */


/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_access.h>
#include <vlc_xml.h>
#include <vlc_strings.h>
#include <vlc_charset.h>
#include <vlc_memstream.h>

#include <assert.h>
#include <ctype.h>
#include <string.h>

#include "playlist.h"

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

static int ReadDir( stream_t *, input_item_node_t * );

static bool ParseTime(xml_reader_t *p_xml_reader, vlc_tick_t* pi_result )
{
    assert( pi_result );
    char *psz_value = NULL;
    char *psz_start = NULL;

    const char *psz_node = NULL;
    const char *psz_txt = NULL;

    int i_subfractions = -1;

    int i_subresult = 0;
    vlc_tick_t i_result = 0;

    do
    {
        psz_txt = xml_ReaderNextAttr( p_xml_reader, &psz_node );
    }
    while( psz_txt && strncasecmp( psz_txt, "VALUE", 5 ) );

    if( !psz_txt )
        return false;

    psz_value = strdup( psz_node );
    psz_start = psz_value;

    while( *psz_value )
    {
        if( isdigit( *psz_value ) )
        {
            i_subresult = i_subresult * 10;
            i_subresult += *psz_value - '0';
            if( i_subfractions != -1 )
                i_subfractions++;
        }
        else if( *psz_value == ':' )
        {
            i_result += i_subresult;
            i_result = i_result * 60;
            i_subresult = 0;
        }
        else if( *psz_value == '.' )
        {
            i_subfractions = 0;
            i_result += i_subresult;
            i_subresult = 0;
        }
        psz_value++;

    }
    if( i_subfractions == -1)
        i_result += i_subresult;

    /* Convert to microseconds */
    if( i_subfractions == -1)
        i_subfractions = 0;
    while( i_subfractions < 6 )
    {
        i_subresult = i_subresult * 10;
        i_subfractions++;
    }
    i_result = i_result * CLOCK_FREQ;
    if( i_subfractions != -1)
        i_result += VLC_TICK_FROM_US( i_subresult );

    free( psz_start );
    *pi_result = i_result;
    return true;
}

static bool ReadElement( xml_reader_t *p_xml_reader, char **ppsz_txt )
{
    const char *psz_node = NULL;

    /* Read the text node */
    int ret = xml_ReaderNextNode( p_xml_reader, &psz_node );
    if( ret <= 0 )
        return false;
    free( *ppsz_txt );
    *ppsz_txt = strdup( psz_node );
    vlc_xml_decode( *ppsz_txt );

    /* Read the end element */
    xml_ReaderNextNode( p_xml_reader, &psz_node );
    /* TODO :
     * Currently we don't check the agreement of start and end element
     * This function is only used to read the element that cannot have child
     * according to the reference.
     */

    return true;
}

static bool PeekASX( stream_t *s )
{
    const uint8_t *p_peek;
    return ( vlc_stream_Peek( s->s, &p_peek, 12 ) == 12
             && !strncasecmp( (const char*) p_peek, "<asx version", 12 ) );
}

/*****************************************************************************
 * Import_ASX: main import function
 *****************************************************************************/


int Import_ASX( vlc_object_t *p_this )
{
    stream_t *p_demux = (stream_t *)p_this;
    char *type = stream_MimeType( p_demux->s );

    if( stream_HasExtension( p_demux, ".asx" )
     || stream_HasExtension( p_demux, ".wax" )
     || stream_HasExtension( p_demux, ".wvx" )
     || (type != NULL && (strcasecmp(type, "video/x-ms-asf") == 0
                       || strcasecmp(type, "audio/x-ms-wax") == 0)
                      && PeekASX( p_demux ) ) )
    {
        msg_Dbg( p_demux, "found valid ASX playlist" );
        free(type);
    }
    else
    {
        free(type);
        return VLC_EGENERIC;
    }

    p_demux->pf_control = PlaylistControl;
    p_demux->pf_readdir = ReadDir;
    return VLC_SUCCESS;
}

static void ProcessEntry( int *pi_n_entry, xml_reader_t *p_xml_reader,
                         input_item_node_t *p_subitems,
                         input_item_t *p_current_input, char *psz_prefix )
{
    const char *psz_node = NULL;
    const char *psz_txt = NULL;
    int i_type;

    char *psz_title = NULL;
    char *psz_artist = NULL;
    char *psz_copyright = NULL;
    char *psz_moreinfo = NULL;
    char *psz_description = NULL;
    char *psz_name = NULL;
    char *psz_mrl = NULL;
    char *psz_href = NULL;

    input_item_t *p_entry = NULL;

    int i_options;
    vlc_tick_t i_start = 0;
    vlc_tick_t i_duration;
    char *ppsz_options[2];

    do
    {
        i_duration = INPUT_DURATION_UNSET;
        i_type = xml_ReaderNextNode( p_xml_reader, &psz_node );

        if( i_type == XML_READER_ERROR || i_type == XML_READER_NONE )
            break;

        if( i_type == XML_READER_STARTELEM )
        {
            /* Metadata Node */
            if( !strncasecmp( psz_node, "TITLE", 5 ) )
            {
                if( !ReadElement( p_xml_reader, &psz_title ) )
                    break;
            }
            else if( !strncasecmp( psz_node, "AUTHOR", 6 ) )
            {
                if( !ReadElement( p_xml_reader, &psz_artist ) )
                    break;
            }
            else if( !strncasecmp( psz_node, "COPYRIGHT", 9 ) )
            {
                if( !ReadElement( p_xml_reader, &psz_copyright ) )
                    break;
            }
            else if( !strncasecmp( psz_node,"MOREINFO", 8 ) )
            {
                do
                {
                    psz_txt = xml_ReaderNextAttr( p_xml_reader, &psz_node );
                }
                while(psz_txt && strncasecmp( psz_txt, "HREF", 4 ) );

                if( !psz_txt )
                {
                    if( !ReadElement( p_xml_reader, &psz_moreinfo ) )
                        break;
                }
                else
                    psz_moreinfo = strdup( psz_node );
                vlc_xml_decode( psz_moreinfo );
            }
            else if( !strncasecmp( psz_node, "ABSTRACT", 8 ) )
            {
                if( !ReadElement( p_xml_reader, &psz_description ) )
                    break;
            }
            else if( !strncasecmp( psz_node, "DURATION", 8 ) )
            {
                if( !ParseTime( p_xml_reader, &i_duration ) )
                   break;
            }
            else if( !strncasecmp( psz_node, "STARTTIME", 9 ) )
            {
                 if( !ParseTime( p_xml_reader, &i_start ) )
                     break;
            }
            /* Reference Node */
            /* All ref node will be converted into an entry */
            else if( !strncasecmp( psz_node, "REF", 3 ) )
            {
                *pi_n_entry = *pi_n_entry + 1;

                if( !psz_title )
                    psz_title = input_item_GetTitle( p_current_input );
                if( !psz_artist )
                    psz_artist = input_item_GetArtist( p_current_input );
                if( !psz_copyright )
                    psz_copyright = input_item_GetCopyright( p_current_input );
                if( !psz_description )
                    psz_description = input_item_GetDescription( p_current_input );

                do
                {
                    psz_txt = xml_ReaderNextAttr( p_xml_reader, &psz_node );
                }
                while( psz_txt != NULL && strncasecmp( psz_txt, "HREF", 4) );
                if( psz_txt == NULL )
                    break;
                psz_href = strdup( psz_node );

                if( asprintf( &psz_name, "%d. %s", *pi_n_entry, psz_title ) == -1)
                    psz_name = strdup( psz_title );
                vlc_xml_decode( psz_href );
                psz_mrl = ProcessMRL( psz_href, psz_prefix );

                /* Add Time information */
                i_options = 0;
                if( i_start )
                {
                    if( asprintf( ppsz_options, ":start-time=%"PRId64 ,
                                  SEC_FROM_VLC_TICK(i_start) ) != -1)
                        i_options++;
                }
                if( i_duration)
                {
                    if( asprintf( ppsz_options + i_options,
                                  ":stop-time=%"PRId64,
                                  SEC_FROM_VLC_TICK(i_start + i_duration) ) != -1)
                        i_options++;
                }

                /* Create the input item */
                p_entry = input_item_NewExt( psz_mrl, psz_name, i_duration,
                                             ITEM_TYPE_UNKNOWN, ITEM_NET_UNKNOWN );
                if( p_entry == NULL )
                    goto end;

                input_item_AddOptions( p_entry, i_options,
                                       (const char **)ppsz_options,
                                       VLC_INPUT_OPTION_TRUSTED );

                /* Add the metadata */
                if( psz_name )
                    input_item_SetTitle( p_entry, psz_name );
                if( psz_artist )
                    input_item_SetArtist( p_entry, psz_artist );
                if( psz_copyright )
                    input_item_SetCopyright( p_entry, psz_copyright );
                if( psz_moreinfo )
                    input_item_SetURL( p_entry, psz_moreinfo );
                if( psz_description )
                    input_item_SetDescription( p_entry, psz_description );
                if( i_duration > 0 )
                    p_entry->i_duration = i_duration;

                input_item_node_AppendItem( p_subitems, p_entry );

                input_item_Release( p_entry );

end:
                while( i_options )
                    free( ppsz_options[--i_options] );
                free( psz_name );
                free( psz_mrl );
            }
        }
    }
    while( i_type != XML_READER_ENDELEM || strncasecmp( psz_node, "ENTRY", 5 ) );

    free( psz_href );
    free( psz_title );
    free( psz_artist );
    free( psz_copyright );
    free( psz_moreinfo );
    free( psz_description );
}

/// this looks for patterns like &name; &#DEC; or &#xHEX;
static bool isXmlEncoded(const char* psz_str)
{
    assert( psz_str != NULL );
    //look for special characters
    if( strpbrk(psz_str, "<>'\"") != NULL )
        return false;

    bool is_escaped = false;
    while( true )
    {
        const char* psz_amp = strchr(psz_str, '&');
        if( psz_amp == NULL )
            break;
        const char* psz_end = strchr(psz_amp, ';');
        if(  psz_end == NULL )
            return false;

        else if(psz_amp[1] == '#')
        {
            if( psz_amp[2] == 'x' )
            {
                const char* psz_ptr = &psz_amp[3];
                if( psz_ptr  ==  psz_end )
                    return false;
                for (  ; psz_ptr < psz_end; psz_ptr++)
                    if( ! isxdigit( *psz_ptr ) )
                        return false;
            }
            else
            {
                const char* psz_ptr = &(psz_amp[2]);
                if( psz_ptr ==  psz_end )
                    return false;
                for (  ; psz_ptr < psz_end; psz_ptr++)
                    if( ! isdigit( *psz_ptr ) )
                        return false;
            }
        }
        else
        {
            const char* psz_ptr = &(psz_amp[1]);
            if( psz_ptr ==  psz_end )
                return false;
            for (  ; psz_ptr < psz_end; psz_ptr++)
                if( ! isalnum( *psz_ptr ) )
                    return false;
        }
        is_escaped = true;
        psz_str = psz_end;
    }
    return is_escaped;
}

static void memstream_puts_xmlencoded(struct vlc_memstream* p_stream, const char* psz_begin, const char* psz_end)
{
    char *psz_tmp = NULL;
    if(psz_end == NULL)
        psz_tmp = strdup( psz_begin );
    else
        psz_tmp = strndup( psz_begin, psz_end - psz_begin );

    if ( psz_tmp == NULL )
        return;

    if( isXmlEncoded( psz_tmp ) )
        vlc_memstream_puts( p_stream, psz_tmp );
    else
    {
        char *psz_tmp_encoded = vlc_xml_encode( psz_tmp );
        if ( !psz_tmp_encoded )
        {
            free( psz_tmp );
            return;
        }
        vlc_memstream_puts( p_stream, psz_tmp_encoded );
        free( psz_tmp_encoded );
    }
    free(psz_tmp);
}

/**
 * ASX doesn't requires to be a strict XML document, this function will
 *  - make tags and attributes upercase
 *  - escape strings when required
 */

VLC_MALLOC static char* ASXToXML( char* psz_source )
{
    bool b_in_string= false;
    char *psz_source_cur = psz_source;
    char *psz_source_old = psz_source;
    char c_string_delim;

    struct vlc_memstream stream_out;
    if( vlc_memstream_open( &stream_out ) != 0 )
        return NULL;

    while ( psz_source_cur != NULL && *psz_source_cur != '\0' )
    {
        psz_source_old = psz_source_cur;
        //search tag start
        if( ( psz_source_cur = strchr( psz_source_cur, '<' ) ) == NULL )
        {
            memstream_puts_xmlencoded(&stream_out, psz_source_old, NULL);
            //vlc_memstream_puts( &stream_out, psz_source_old );
            break;
        }

        memstream_puts_xmlencoded(&stream_out, psz_source_old, psz_source_cur);
        psz_source_old = psz_source_cur;

        //skip if comment, no need to copy them to the output.
        if( strncmp( psz_source_cur, "<!--", 4 ) == 0 )
        {
            psz_source_cur += 4;
            psz_source_cur =  strstr( psz_source_cur, "-->" );
            if( psz_source_cur == NULL)
                break;
            else
            {
                psz_source_cur += 3;
                continue;
            }
        }
        else
        {
            vlc_memstream_putc( &stream_out, '<' );
            psz_source_cur++;
        }

        for (  ; *psz_source_cur != '\0'; psz_source_cur++ )
        {
            if( b_in_string == false )
            {
                if( *psz_source_cur == '>')
                {
                    vlc_memstream_putc( &stream_out, '>' );
                    psz_source_cur++;
                    break;
                }
                if( *psz_source_cur == '"' || *psz_source_cur == '\'' )
                {
                    c_string_delim = *psz_source_cur;
                    b_in_string = true;
                    vlc_memstream_putc( &stream_out, c_string_delim );
                }
                else
                {
                    //convert tag and attributes to upper case
                    vlc_memstream_putc( &stream_out, vlc_ascii_toupper( *psz_source_cur ) );
                }
            }
            else
            {
                psz_source_old = psz_source_cur;
                psz_source_cur = strchr( psz_source_cur, c_string_delim );
                if( psz_source_cur == NULL )
                    break;

                memstream_puts_xmlencoded(&stream_out, psz_source_old, psz_source_cur);
                vlc_memstream_putc( &stream_out, c_string_delim );
                b_in_string = false;
            }
        }
    }
    if( vlc_memstream_close( &stream_out ) != 0 )
        return NULL;

    return stream_out.ptr;
}

static char *detectXmlEncoding( const char *psz_xml )
{
    const char *psz_keyword_begin = NULL;
    const char *psz_keyword_end = NULL;

    const char *psz_value_begin = NULL;
    const char *psz_value_end = NULL;

    psz_xml += strspn( psz_xml, " \n\r\t" );
    if( strncasecmp( psz_xml, "<?xml", 5 ) != 0 )
        return NULL;
    psz_xml += 5;

    const char *psz_end = strstr( psz_xml, "?>" );
    if( psz_end == NULL )
        return NULL;

    while( psz_xml < psz_end )
    {
        psz_keyword_begin = psz_xml = psz_xml + strspn( psz_xml, " \n\r\t" );
        if( *psz_xml == '\0' )
            return NULL;
        psz_keyword_end = psz_xml = psz_xml + strcspn( psz_xml, " \n\r\t=" );
        if( *psz_xml == '\0' )
            return NULL;

        psz_xml += strspn( psz_xml, " \n\r\t" );
        if( *psz_xml != '=' )
            return NULL;
        psz_xml++;

        psz_xml += strspn( psz_xml, " \n\r\t" );
        char quote = *psz_xml;
        if( quote != '"' && quote != '\'' )
            return NULL;

        psz_value_begin = ++psz_xml;
        psz_value_end = psz_xml = strchr( psz_xml, quote );
        if( psz_xml == NULL )
            return NULL;
        psz_xml++;

        if( strncasecmp( psz_keyword_begin, "encoding", psz_keyword_end -  psz_keyword_begin ) == 0
             && ( psz_value_end -psz_value_begin) > 0 )
        {
            return strndup(psz_value_begin, psz_value_end -psz_value_begin);
        }
    }

    return NULL;
}


static stream_t* PreparseStream( stream_t *p_demux )
{
    stream_t *s = p_demux->s;
    uint64_t streamSize;
    static const size_t maxsize = 1024 * 1024;

    if( vlc_stream_GetSize( s, &streamSize ) != VLC_SUCCESS)
        streamSize = maxsize;

     // Don't attempt to convert/store huge streams
     if( streamSize > maxsize )
         return NULL;
     char* psz_source = malloc( streamSize + 1 * sizeof( *psz_source ) );
     if ( unlikely( psz_source == NULL ) )
         return NULL;
     size_t i_read = 0;
     do
     {
         ssize_t i_ret = vlc_stream_Read( s, psz_source + i_read,
                                          streamSize > 1024 ? 1024 : streamSize );
         if ( i_ret <= 0 )
             break;
         assert( (size_t)i_ret <= streamSize );
         streamSize -= i_ret;
         i_read += i_ret;
     } while ( streamSize > 0 );
     psz_source[i_read] = 0;


     char *encoding = detectXmlEncoding( psz_source );
     if( encoding != NULL )
     {
         if( strcasecmp( encoding, "UTF-8" ) == 0 )
            free( encoding );
         else
         {
            //strip xml prologue to avoid double conversion
            char *tmp = strstr( psz_source, "?>" );
            if ( tmp )
                tmp += 2;
            else
                tmp = psz_source;
            tmp = FromCharset( encoding, tmp, strlen( tmp ) );
            free( psz_source );
            free( encoding );
            if ( !tmp )
                return NULL;
            psz_source = tmp;
         }
     }
     else if( !IsUTF8( psz_source ) )
     {
         char *tmp = FromLocaleDup( psz_source );
         free( psz_source );
         if( !tmp )
             return NULL;
         psz_source = tmp;
     }

    char *psz_source_xml = ASXToXML( psz_source );
    free( psz_source );
    if( psz_source_xml == NULL )
         return NULL;

     stream_t * p_stream = vlc_stream_MemoryNew( p_demux, (uint8_t*)psz_source_xml, strlen(psz_source_xml), false );
     return p_stream;
}

static int ReadDir( stream_t *p_demux, input_item_node_t *p_subitems )
{
    if (unlikely(p_demux->psz_url == NULL))
        return VLC_EGENERIC;

    const char *psz_node = NULL;
    char *psz_txt = NULL;
    char *psz_base = strdup( p_demux->psz_url );
    if (unlikely(psz_base == NULL))
        return VLC_ENOMEM;

    char *psz_title_asx = NULL;
    char *psz_entryref = NULL;

    xml_reader_t *p_xml_reader = NULL;
    input_item_t *p_current_input = GetCurrentItem( p_demux );
    stream_t* p_stream = PreparseStream( p_demux );

    bool b_first_node = false;
    int i_type;
    int i_n_entry = 0;

    p_xml_reader = xml_ReaderCreate( p_demux, p_stream ? p_stream
                                                       : p_demux->s );
    if( !p_xml_reader )
    {
        msg_Err( p_demux, "Cannot parse ASX input file as XML");
        goto error;
    }

    do
    {
        i_type = xml_ReaderNextNode( p_xml_reader, &psz_node );
        if( i_type == XML_READER_ERROR || i_type == XML_READER_NONE )
            break;

        if( i_type == XML_READER_STARTELEM )
        {
            if( !b_first_node )
            {
                if(!strncasecmp( psz_node, "ASX", 3 ) )
                    b_first_node = true;
                else
                {
                    msg_Err( p_demux, "invalid root node" );
                    goto error;
                }
            }

            /* Metadata Node Handler */
            if( !strncasecmp( psz_node, "TITLE", 5 ) )
            {
                if( ! ReadElement( p_xml_reader, &psz_title_asx ) )
                    break;
                input_item_SetTitle( p_current_input, psz_title_asx );
            }
            else if( !strncasecmp( psz_node, "AUTHOR", 6 ) )
            {
                if( ! ReadElement( p_xml_reader, &psz_txt ) )
                    break;
                input_item_SetArtist( p_current_input, psz_txt );
            }
            else if( !strncasecmp( psz_node, "COPYRIGHT", 9 ) )
            {
                if( ! ReadElement( p_xml_reader, &psz_txt ) )
                    break;
                input_item_SetCopyright( p_current_input, psz_txt );
            }
            else if( !strncasecmp( psz_node, "MOREINFO", 8 ) )
            {
                const char *psz_tmp;
                do
                {
                    psz_tmp = xml_ReaderNextAttr( p_xml_reader, &psz_node );
                }
                while( psz_tmp && strncasecmp( psz_tmp, "HREF", 4 ) );

                if( !psz_tmp )  // If HREF attribute doesn't exist
                {
                    if( ! ReadElement( p_xml_reader, &psz_txt ) )
                        break;
                }
                else
                    psz_txt = strdup( psz_node );

                vlc_xml_decode( psz_txt );
                input_item_SetURL( p_current_input, psz_txt );
            }
            else if( !strncasecmp( psz_node, "ABSTRACT", 8 ) )
            {
                if( ! ReadElement( p_xml_reader, &psz_txt ) )
                    break;
                input_item_SetDescription( p_current_input, psz_txt );
            }
            else
            /* Base Node handler */
            if( !strncasecmp( psz_node, "BASE", 4 ) )
            {
                if( ! ReadElement( p_xml_reader, &psz_base ) )
                    break;
            }
            else
            /* Entry Ref Handler */
            if( !strncasecmp( psz_node, "ENTRYREF", 7 ) )
            {
                const char *psz_tmp;
                do
                {
                    psz_tmp = xml_ReaderNextAttr( p_xml_reader, &psz_node );
                }
                while( psz_tmp && !strncasecmp( psz_tmp, "HREF", 4 ) );
                if( ! psz_tmp )
                    break;

                /* Create new input item */
                input_item_t *p_input;
                psz_txt = strdup( psz_node );
                vlc_xml_decode( psz_txt );
                p_input = input_item_New( psz_txt, psz_title_asx );
                input_item_node_AppendItem( p_subitems, p_input );

                input_item_Release( p_input );
            }
            else
            /* Entry Handler */
            if( !strncasecmp( psz_node, "ENTRY", 5 ) )
            {
                ProcessEntry( &i_n_entry, p_xml_reader, p_subitems,
                              p_current_input, psz_base);
            }
        /* FIXME Unsupported elements
            PARAM
            EVENT
            REPEAT
            ENDMARK
            STARTMARK
        */

        }
    }
    while( i_type != XML_READER_ENDELEM || strncasecmp( psz_node, "ASX", 3 ) );

error:
    free( psz_base );
    free( psz_title_asx );
    free( psz_entryref );
    free( psz_txt );

    if( p_xml_reader)
        xml_ReaderDelete( p_xml_reader );
    if( p_stream )
        vlc_stream_Delete( p_stream );

    return 0;
}

Messung
CHZG
93979795

¤ Dauer der Verarbeitung: 0.10 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.