Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  theme_loader.cpp   Sprache: C

 

/*****************************************************************************
 * theme_loader.cpp
 *****************************************************************************
 * Copyright (C) 2003 the VideoLAN team
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
 *          Olivier Teulière <ipkiss@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU 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.
 *****************************************************************************/


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

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <memory>

#include <vlc_common.h>
#include <vlc_configuration.h>
#include <vlc_fs.h>
#include <vlc_url.h>
#include <vlc_stream_extractor.h>
#include <vlc_charset.h>

#include "theme_loader.hpp"
#include "theme.hpp"
#include "../parser/builder.hpp"
#include "../parser/skin_parser.hpp"
#include "../src/os_factory.hpp"
#include "../src/vlcproc.hpp"
#include "../src/window_manager.hpp"

#define DEFAULT_XML_FILE "theme.xml"
#define WINAMP2_XML_FILE "winamp2.xml"

#if defined( __OS2__ )
/// Wrapper around FromLocale, to avoid the need to call LocaleFree()
static inline std::string sFromLocale( const std::string &rLocale )
{
    const char *s = FromLocale( rLocale.c_str() );
    std::string res = s;
    LocaleFree( s );
    return res;
}
#endif


/* Recursive make directory
 * Abort if you get an ENOENT errno somewhere in the middle
 * e.g. ignore error "mkdir on existing directory"
 *
 * return 1 if OK, 0 on error
 */

static int makedir( const char *newdir )
{
    int ret = vlc_mkdir_parent(newdir, 0775);
    if (ret == 0)
        return 1;
    fprintf(stderr, "couldn't create directory %s\n", newdir);
    return 0;
}

bool ThemeLoader::load( const std::string &fileName )
{
    std::string path = getFilePath( fileName );

    //Before all, let's see if the file is present
    struct stat p_stat;
    if( vlc_stat( fileName.c_str(), &p_stat ) )
        return false;

    // First, we try to un-targz the file, and if it fails we hope it's a XML
    // file...

    if( ! extract( fileName ) && ! parse( path, fileName ) )
        return false;

    auto &pNewTheme = getIntf()->p_sys->p_theme;
    if( !pNewTheme )
        return false;

    // Restore the theme configuration
    getIntf()->p_sys->p_theme->loadConfig();

    // Retain new loaded skins in config
    config_PutPsz( "skins2-last", fileName.c_str() );

    return true;
}

bool ThemeLoader::extract( const std::string &fileName )
{
    bool result = true;
    std::string tempPath = getTmpDir();
    if( tempPath.empty() )
        return false;

    if( unarchive( fileName, tempPath ) == false )
    {
        msg_Err( getIntf(), "extraction from %s failed", fileName.c_str() );
        deleteTempFiles( tempPath );
        return false;
    }

    std::string path;
    std::string xmlFile;
    OSFactory *pOsFactory = OSFactory::instance( getIntf() );
    // Find the XML file in the theme
    if( findFile( tempPath, DEFAULT_XML_FILE, xmlFile ) )
    {
        path = getFilePath( xmlFile );
    }
    else
    {
        // No XML file, check if it is a winamp2 skin
        std::string mainBmp;
        if( findFile( tempPath, "main.bmp", mainBmp ) )
        {
            msg_Dbg( getIntf(), "trying to load a winamp2 skin" );
            path = getFilePath( mainBmp );

            // Look for winamp2.xml in the resource path
            std::list<std::string> resPath = pOsFactory->getResourcePath();
            std::list<std::string>::const_iterator it;
            for( it = resPath.begin(); it != resPath.end(); ++it )
            {
                if( findFile( *it, WINAMP2_XML_FILE, xmlFile ) )
                    break;
            }
        }
    }

    if( !xmlFile.empty() )
    {
        // Parse the XML file
        if (! parse( path, xmlFile ) )
        {
            msg_Err( getIntf(), "error while parsing %s", xmlFile.c_str() );
            result = false;
        }
    }
    else
    {
        msg_Err( getIntf(), "no XML found in theme %s", fileName.c_str() );
        result = false;
    }

    // Clean-up
    deleteTempFiles( tempPath );
    return result;
}

bool ThemeLoader::unarchive( const std::string& fileName, const std::string &tempPath )
{
#define UPTR_HELPER(type,deleter) []( type * data ) { \
        return std::unique_ptr< type, decltype( deleter )> ( data, deleter ); }

    auto make_input_node_ptr = UPTR_HELPER( input_item_node_t, &input_item_node_Delete );
    auto make_input_item_ptr = UPTR_HELPER( input_item_t, &input_item_Release );
    auto make_stream_ptr = UPTR_HELPER( stream_t, &vlc_stream_Delete );
    auto make_cstr_ptr = UPTR_HELPER( char, &std::free );

#undef UPTR_HELPER

    auto uri = make_cstr_ptr( vlc_path2uri( fileName.c_str(), "file" ) );
    if( !uri )
    {
        msg_Err( getIntf(), "unable to convert %s to local URI",
                            fileName.c_str() );
        return false;
    }

    auto input = make_stream_ptr( vlc_stream_NewURL( getIntf(), uri.get() ) );
    if( !input )
    {
        msg_Err( getIntf(), "unable to open %s", uri.get() );
        return false;
    }

    stream_t* stream = input.get();
    if( vlc_stream_directory_Attach( &stream, NULL, NULL, 0 ) )
    {
        msg_Err( getIntf(), "unable to attach stream_directory, treat as XML!" );
    }
    else
    {
        input.release();
        input.reset( stream );

        auto item = make_input_item_ptr( input_item_New( "vlc://dummy", "vlc://dummy" ) );
        auto node = make_input_node_ptr( (input_item_node_t*)std::calloc( 1, sizeof( input_item_node_t ) ) );

        if( !item || !node )
            return false;

        input_item_AddOption( item.get(), "ignore-filetypes=\"\"", VLC_INPUT_OPTION_TRUSTED );
        input_item_AddOption( item.get(), "extractor-flatten", VLC_INPUT_OPTION_TRUSTED );
        node->p_item = item.release();

        if( vlc_stream_ReadDir( input.get(), node.get() ) )
        {
            msg_Err( getIntf(), "unable to read items in %s", uri.get() );
            return false;
        }

        for( int i = 0; i < node->i_children; ++i )
        {
            auto child = node->pp_children[i]->p_item;
            auto child_stream = make_stream_ptr( vlc_stream_NewMRL( getIntf(), child->psz_uri ) );
            if( !child_stream )
            {
                msg_Err( getIntf(), "unable to open %s for reading", child->psz_name );
                return false;
            }

#if defined( _WIN32 ) || defined( __OS2__ )
            if( strchr( child->psz_name, '\\' ) )
                return false;
#endif

            auto base = make_cstr_ptr( vlc_path2uri( tempPath.c_str(), "file" ) );
            if( !base )
                return false;

            std::string base_uri = base.get();
            if( base_uri.empty() || base_uri.back() != '/' )
                base_uri += '/';

            /* URI metacharacters in member names are filename data. */
            std::string ref;
            for( const char *component = child->psz_name; *component; )
            {
                size_t len = strcspn( component, "/" );
                auto encoded = make_cstr_ptr( vlc_uri_encode(
                    std::string( component, len ).c_str() ) );
                if( !encoded )
                    return false;

                ref += encoded.get();
                component += len;
                if( *component == '/' )
                    ref += *component++;
            }

            auto resolved = make_cstr_ptr( vlc_uri_resolve( base_uri.c_str(), ref.c_str() ) );
            if( !resolved )
                return false;

            if( std::string( resolved.get() ).compare( 0, base_uri.size(), base_uri ) != 0 )
            {
                msg_Err( getIntf(), "Invalid resolved path from archive: %s", resolved.get() );
                return false;
            }

            /* Use the path validated through the uri resolution */

            auto out_path = tempPath + "/" + child->psz_name;

            { /* create directory tree */
                auto out_directory = out_path.substr( 0, out_path.find_last_of( '/' ) );

                if( makedir( out_directory.c_str() ) == false )
                {
                    msg_Err( getIntf(), "failed to create directory tree for %s (%s)",
                             out_path.c_str(), out_directory.c_str() );

                    return false;
                }
            }

            { /* write data to disk */
                std::string contents;

                char buf[1024];
                ssize_t n;

                while( ( n = vlc_stream_Read( child_stream.get(), buf, sizeof buf ) ) > 0 )
                    contents.append( buf, n );

                std::ofstream out_stream( out_path, std::ios::binary );

                if( out_stream.write( contents.data(), contents.size() ) )
                {
                    msg_Dbg( getIntf(), "finished writing %zu bytes to %s",
                        size_t{ contents.size() }, out_path.c_str() );
                }
                else
                {
                    msg_Err( getIntf(), "unable to write %zu bytes to %s",
                        size_t{ contents.size() }, out_path.c_str() );
                    return false;
                }
            }
        }
    }

    return true;
}

void ThemeLoader::deleteTempFiles( const std::string &path )
{
    OSFactory::instance( getIntf() )->rmDir( path );
}

bool ThemeLoader::parse( const std::string &path, const std::string &xmlFile )
{
    // File loaded
    msg_Dbg( getIntf(), "using skin file: %s", xmlFile.c_str() );

    // Start the parser
    SkinParser parser( getIntf(), xmlFile, path );
    if( ! parser.parse() )
        return false;

    // Build and store the theme
    Builder builder( getIntf(), parser.getData(), path );
    getIntf()->p_sys->p_theme.reset(builder.build());

    return true;
}


std::string ThemeLoader::getFilePath( const std::string &rFullPath )
{
    OSFactory *pOsFactory = OSFactory::instance( getIntf() );
    const std::string &sep = pOsFactory->getDirSeparator();
    // Find the last separator ('/' or '\')
    std::string::size_type p = rFullPath.rfind( sep, rFullPath.size() );
    std::string basePath;
    if( p != std::string::npos )
    {
        if( p < rFullPath.size() - 1)
        {
            basePath = rFullPath.substr( 0, p );
        }
        else
        {
            basePath = rFullPath;
        }
    }
    return basePath;
}

bool ThemeLoader::findFile( const std::string &rootDir, const std::string &rFileName,
                            std::string &themeFilePath )
{
    // Path separator
    const std::string &sep = OSFactory::instance( getIntf() )->getDirSeparator();

    const char *pszDirContent;

    // Open the dir
    vlc_DIR *pCurrDir = vlc_opendir( rootDir.c_str() );

    if( pCurrDir == NULL )
    {
        // An error occurred
        msg_Dbg( getIntf(), "cannot open directory %s", rootDir.c_str() );
        return false;
    }

    // While we still have entries in the directory
    while( ( pszDirContent = vlc_readdir( pCurrDir ) ) != NULL )
    {
        std::string newURI = rootDir + sep + pszDirContent;

        // Skip . and ..
        if( std::string( pszDirContent ) != "." &&
            std::string( pszDirContent ) != ".." )
        {
#if defined( S_ISDIR )
            struct stat stat_data;

            if( ( vlc_stat( newURI.c_str(), &stat_data ) == 0 )
             && S_ISDIR(stat_data.st_mode) )
#elif defined( DT_DIR )
            if( pDirContent->d_type & DT_DIR )
#else
            if( 0 )
#endif
            {
                // Can we find the file in this subdirectory?
                if( findFile( newURI, rFileName, themeFilePath ) )
                {
                    vlc_closedir( pCurrDir );
                    return true;
                }
            }
            else
            {
                // Found the theme file?
                if( rFileName == std::string( pszDirContent ) )
                {
                    themeFilePath = std::move(newURI);
                    vlc_closedir( pCurrDir );
                    return true;
                }
            }
        }
    }

    vlc_closedir( pCurrDir );
    return false;
}

// FIXME: could become a skins2 OS factory function or a vlc core function
std::string ThemeLoader::getTmpDir( )
{
#if defined( _WIN32 )
    wchar_t *tmpdir = _wtempnam( NULL, L"vlt" );
    if( tmpdir == NULL )
        return "";
    char* utf8 = FromWide( tmpdir );
    free( tmpdir );
    std::string tempPath( utf8 ? utf8 : "" );
    free( utf8 );
    return tempPath;

#elif defined( __OS2__ )
    char *tmpdir = tempnam( NULL, "vlt" );
    if( tmpdir == NULL )
        return "";
    std::string tempPath( sFromLocale( tmpdir ));
    free( tmpdir );
    return tempPath;

#else
    char templ[] = "/tmp/vltXXXXXX";
    char *tmpdir = mkdtemp( templ );
    return std::string( tmpdir ? tmpdir : "");
#endif
}



Messung
CHZG
85988790

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104857
#Domains=418202