Commit ce32ffa3 authored by Olivier Teulière's avatar Olivier Teulière

* skins2/src/theme_loader.cpp: .vlt files can now contain directories

   and subdirectories. When loading a skin, the "theme.xml" file will be
   searched recursively, and the first one to be found is used.

 * skins2/*: Do not 'cd' anymore to the temporary directory where the
   .vlt is extracted (instead, we transform the relative paths specified
   in the XML file into absolute paths).
parent a44edfa9
......@@ -28,8 +28,10 @@
#define SKINS_DTD_VERSION "2.0"
SkinParser::SkinParser( intf_thread_t *pIntf, const string &rFileName ):
XMLParser( pIntf, rFileName ), m_xOffset( 0 ), m_yOffset( 0 )
SkinParser::SkinParser( intf_thread_t *pIntf, const string &rFileName,
const string &rPath ):
XMLParser( pIntf, rFileName ), m_xOffset( 0 ), m_yOffset( 0 ),
m_path( rPath )
{
}
......@@ -46,14 +48,16 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr )
else if( rName == "Bitmap" )
{
const BuilderData::Bitmap bitmap( attr["id"] , attr["file"],
const BuilderData::Bitmap bitmap( attr["id"] ,
ConvertFileName( attr["file"] ),
ConvertColor( attr["alphacolor"] ) );
m_data.m_listBitmap.push_back( bitmap );
}
else if( rName == "BitmapFont" )
{
const BuilderData::BitmapFont font( attr["id"] , attr["file"],
const BuilderData::BitmapFont font( attr["id"],
ConvertFileName( attr["file"] ),
attr["type"] );
m_data.m_listBitmapFont.push_back( font );
}
......@@ -84,7 +88,8 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr )
else if( rName == "Font" )
{
const BuilderData::Font fontData( attr["id"], attr["file"],
const BuilderData::Font fontData( attr["id"],
ConvertFileName( attr["file"] ),
atoi( attr["size"] ) );
m_data.m_listFont.push_back( fontData );
}
......@@ -259,6 +264,11 @@ int SkinParser::ConvertColor( const char *transcolor ) const
return ( iRed << 16 | iGreen << 8 | iBlue );
}
string SkinParser::ConvertFileName( const char *fileName ) const
{
return m_path + string( fileName );
}
const string SkinParser::generateId() const
{
static int i = 1;
......
......@@ -2,7 +2,7 @@
* skin_parser.hpp
*****************************************************************************
* Copyright (C) 2004 VideoLAN
* $Id: skin_parser.hpp,v 1.2 2004/03/01 18:33:31 asmax Exp $
* $Id$
*
* Authors: Cyril Deguet <asmax@via.ecp.fr>
*
......@@ -33,7 +33,8 @@
class SkinParser: public XMLParser
{
public:
SkinParser( intf_thread_t *pIntf, const string &rFileName );
SkinParser( intf_thread_t *pIntf, const string &rFileName,
const string &rPath );
virtual ~SkinParser() {}
const BuilderData &getData() const { return m_data; }
......@@ -52,14 +53,18 @@ class SkinParser: public XMLParser
int m_curLayer;
/// Set of used id
set<string> m_idSet;
/// Path of the XML file being parsed
const string m_path;
/// Callbacks
virtual void handleBeginElement( const string &rName, AttrList_t &attr );
virtual void handleBeginElement( const string &rName,
AttrList_t &attr );
virtual void handleEndElement( const string &rName );
/// Helper functions
bool ConvertBoolean( const char *value ) const;
int ConvertColor( const char *transcolor ) const;
string ConvertFileName( const char *fileName ) const;
/// Generate a new id
const string generateId() const;
......
......@@ -29,13 +29,20 @@
#include "../src/os_factory.hpp"
#include "../src/window_manager.hpp"
#include <fcntl.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#if !defined( WIN32 )
# include <unistd.h>
#else
# include <direct.h>
#endif
#if (!defined( WIN32 ) || defined(__MINGW32__))
/* Mingw has its own version of dirent */
# include <dirent.h>
#endif
#if defined( HAVE_ZLIB_H )
# include <zlib.h>
......@@ -134,9 +141,9 @@ bool ThemeLoader::extract( const string &fileName )
if( ! extractTarGz( fileName, tempPath ) )
return false;
// Parse the extracted XML file
const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
if( ! parse( tempPath + sep + string( DEFAULT_XML_FILE ) ) )
// Find the XML file and parse it
string xmlFile;
if( ! findThemeFile( tempPath, xmlFile ) || ! parse( xmlFile ) )
{
msg_Err( getIntf(), "%s doesn't contain a " DEFAULT_XML_FILE " file",
fileName.c_str() );
......@@ -162,28 +169,24 @@ bool ThemeLoader::parse( const string &xmlFile )
// File loaded
msg_Dbg( getIntf(), "Using skin file: %s", xmlFile.c_str() );
// Save current working directory
char *cwd = new char[PATH_MAX];
getcwd( cwd, PATH_MAX );
// Change current working directory to xml file
// Extract the path of the XML file
string path;
const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
unsigned int p = xmlFile.rfind( sep, xmlFile.size() );
if( p != string::npos )
{
string path = xmlFile.substr( 0, p );
chdir( path.c_str() );
path = xmlFile.substr( 0, p + 1 );
}
else
{
path = "";
}
// Start the parser
SkinParser parser( getIntf(), xmlFile );
bool ret = parser.parse();
if( !ret )
SkinParser parser( getIntf(), xmlFile, path );
if( ! parser.parse() )
{
msg_Err( getIntf(), "Failed to parse %s", xmlFile.c_str() );
// Set old working directory to current
chdir( cwd );
delete[] cwd;
return false;
}
......@@ -191,13 +194,72 @@ bool ThemeLoader::parse( const string &xmlFile )
Builder builder( getIntf(), parser.getData() );
getIntf()->p_sys->p_theme = builder.build();
// Set old working directory to current.
// We need to do that _after_ calling Builder:build(), otherwise the
// opening of the files will fail
chdir( cwd );
delete[] cwd;
return true;
}
bool ThemeLoader::findThemeFile( const string &rootDir, string &themeFilePath )
{
// Path separator
const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
DIR *pCurrDir;
struct dirent *pDirContent;
// Open the dir
pCurrDir = opendir( rootDir.c_str() );
if( pCurrDir == NULL )
{
// An error occurred
msg_Dbg( getIntf(), "Cannot open directory %s", rootDir.c_str() );
return false;
}
// Get the first directory entry
pDirContent = readdir( pCurrDir );
// While we still have entries in the directory
while( pDirContent != NULL )
{
string newURI = rootDir + sep + pDirContent->d_name;
// Skip . and ..
if( string( pDirContent->d_name ) != "." &&
string( pDirContent->d_name ) != ".." )
{
#if defined( S_ISDIR )
struct stat stat_data;
stat( newURI.c_str(), &stat_data );
if( S_ISDIR(stat_data.st_mode) )
#elif defined( DT_DIR )
if( pDirContent->d_type == DT_DIR )
#else
if( 0 )
#endif
{
// Can we find the theme file in this subdirectory?
if( findThemeFile( newURI, themeFilePath ) )
{
return true;
}
}
else
{
// Found the theme file?
if( string( DEFAULT_XML_FILE ) ==
string( pDirContent->d_name ) )
{
themeFilePath = newURI;
return true;
}
}
}
pDirContent = readdir( pCurrDir );
}
return false;
}
......
......@@ -2,7 +2,7 @@
* theme_loader.hpp
*****************************************************************************
* Copyright (C) 2003 VideoLAN
* $Id: theme_loader.hpp,v 1.1 2004/01/03 23:31:34 asmax Exp $
* $Id$
*
* Authors: Cyril Deguet <asmax@via.ecp.fr>
* Olivier Teulière <ipkiss@via.ecp.fr>
......@@ -39,11 +39,24 @@ class ThemeLoader: public SkinObject
private:
#if defined( HAVE_ZLIB_H )
bool extractTarGz( const string &tarFile, const string &rootDir );
/// Extract files from an archive (currently only handles tar.gz)
bool extract( const string &fileName );
/// Extract files from a tar.gz archive
bool extractTarGz( const string &tarFile, const string &rootDir );
/// Clean up the temporary files created by the extraction
void deleteTempFiles( const string &path );
#endif
/// Parse the XML file given as a parameter and build the skin
bool parse( const string &xmlFile );
/// Recursively look for the XML file from rootDir.
/// The first corresponding file found will be chosen and themeFilePath
/// will be updated accordingly.
/// The method returns true if a theme file was found, false otherwise
bool findThemeFile( const string &rootDir, string &themeFilePath );
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment