1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: theme_loader.cpp,v 1.3 2004/01/11 00:21:22 asmax Exp $
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 #include "theme_loader.hpp"
27 #include "../parser/builder.hpp"
28 #include "../parser/parser_context.hpp"
29 #include "../src/os_factory.hpp"
30 #include "../src/window_manager.hpp"
40 #if defined( HAVE_ZLIB_H )
43 int gzopen_frontend( char *pathname, int oflags, int mode );
44 #if defined( HAVE_LIBTAR_H )
48 int tar_open ( TAR **t, char *pathname, int oflags );
49 int tar_extract_all ( TAR *t, char *prefix );
50 int tar_close ( TAR *t );
54 #define DEFAULT_XML_FILE "theme.xml"
59 int yylex( void *pContext );
62 bool ThemeLoader::load( const string &fileName )
64 // First, we try to un-targz the file, and if it fails we hope it's a XML
66 #if defined( HAVE_ZLIB_H )
67 if( ! extract( fileName ) && ! parse( fileName ) )
70 if( ! parse( fileName ) )
75 // Check if the skin to load is in the config file, to load its config
76 char *skin_last = config_GetPsz( getIntf(), "skin_last" );
77 if( skin_last != NULL && fileName == (string)skin_last )
79 getIntf()->p_sys->p_theme->LoadConfig();
83 config_PutPsz( getIntf(), "skin_last", fileName.c_str() );
84 config_SaveConfigFile( getIntf(), "skins" );
87 Theme *pNewTheme = getIntf()->p_sys->p_theme;
90 // Used to anchor the windows at the beginning
91 pNewTheme->getWindowManager().stopMove();
93 pNewTheme->getWindowManager().showAll();
100 #if defined( HAVE_ZLIB_H )
101 bool ThemeLoader::extractTarGz( const string &tarFile, const string &rootDir )
104 #if defined( HAVE_LIBTAR_H )
105 tartype_t gztype = { (openfunc_t) gzopen_frontend, (closefunc_t) gzclose,
106 (readfunc_t) gzread, (writefunc_t) gzwrite };
108 if( tar_open( &t, (char *)tarFile.c_str(), &gztype, O_RDONLY, 0,
111 if( tar_open( &t, (char *)tarFile.c_str(), O_RDONLY ) == -1 )
117 if( tar_extract_all( t, (char *)rootDir.c_str() ) != 0 )
123 if( tar_close( t ) != 0 )
132 bool ThemeLoader::extract( const string &fileName )
134 char *tmpdir = tempnam( NULL, "vlt" );
135 string tempPath = tmpdir;
138 // Extract the file in a temporary directory
139 if( ! extractTarGz( fileName, tempPath ) )
142 // Parse the extracted XML file
143 const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
144 if( ! parse( tempPath + sep + string( DEFAULT_XML_FILE ) ) )
146 msg_Err( getIntf(), "%s doesn't contain a " DEFAULT_XML_FILE " file",
148 deleteTempFiles( tempPath );
153 deleteTempFiles( tempPath );
158 void ThemeLoader::deleteTempFiles( const string &path )
160 OSFactory::instance( getIntf() )->rmDir( path );
162 #endif // HAVE_ZLIB_H
165 bool ThemeLoader::parse( const string &xmlFile )
167 // Things to do before loading theme
168 // getIntf()->p_sys->p_theme->OnLoadTheme();
169 // Set the file to parse
170 yyin = fopen( xmlFile.c_str(), "r" );
173 // Skin cannot be opened
174 msg_Err( getIntf(), "Cannot open the specified skin file: %s",
180 msg_Dbg( getIntf(), "Using skin file: %s", xmlFile.c_str() );
182 // Save current working directory
183 char *cwd = new char[PATH_MAX];
184 getcwd( cwd, PATH_MAX );
186 // Change current working directory to xml file
187 const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
188 unsigned int p = xmlFile.rfind( sep, xmlFile.size() );
189 if( p != string::npos )
191 string path = xmlFile.substr( 0, p );
192 chdir( path.c_str() );
196 ParserContext context( getIntf() );
197 int lex = yylex( &context );
202 // Set old working directory to current
206 msg_Warn( getIntf(), "yylex failed: %i", lex );
210 // Build and store the theme
211 Builder builder( getIntf(), context.m_data );
212 getIntf()->p_sys->p_theme = builder.build();
214 // Set old working directory to current.
215 // We need to do that _after_ calling Builder:build(), otherwise the
216 // opening of the files will fail
224 #if !defined( HAVE_LIBTAR_H ) && defined( HAVE_ZLIB_H )
227 # define mkdir(dirname,mode) _mkdir(dirname)
230 /* Values used in typeflag field */
231 #define REGTYPE '0' /* regular file */
232 #define AREGTYPE '\0' /* regular file */
233 #define DIRTYPE '5' /* directory */
235 #define BLOCKSIZE 512
239 char name[100]; /* 0 */
240 char mode[8]; /* 100 */
241 char uid[8]; /* 108 */
242 char gid[8]; /* 116 */
243 char size[12]; /* 124 */
244 char mtime[12]; /* 136 */
245 char chksum[8]; /* 148 */
246 char typeflag; /* 156 */
247 char linkname[100]; /* 157 */
248 char magic[6]; /* 257 */
249 char version[2]; /* 263 */
250 char uname[32]; /* 265 */
251 char gname[32]; /* 297 */
252 char devmajor[8]; /* 329 */
253 char devminor[8]; /* 337 */
254 char prefix[155]; /* 345 */
260 char buffer[BLOCKSIZE];
261 struct tar_header header;
265 /* helper functions */
266 int getoct( char *p, int width );
267 int makedir( char *newdir );
269 int tar_open( TAR **t, char *pathname, int oflags )
271 gzFile f = gzopen( pathname, "rb" );
274 fprintf( stderr, "Couldn't gzopen %s\n", pathname );
278 *t = (gzFile *)malloc( sizeof(gzFile) );
284 int tar_extract_all( TAR *t, char *prefix )
286 union tar_buffer buffer;
287 int len, err, getheader = 1, remaining = 0;
288 FILE *outfile = NULL;
289 char fname[BLOCKSIZE + PATH_MAX];
293 len = gzread( *t, &buffer, BLOCKSIZE );
296 fprintf( stderr, "%s\n", gzerror(*t, &err) );
300 * Always expect complete blocks to process
301 * the tar information.
303 if( len != 0 && len != BLOCKSIZE )
305 fprintf( stderr, "gzread: incomplete block read\n" );
310 * If we have to get a tar header
315 * If we met the end of the tar
316 * or the end-of-tar block, we are done
318 if( (len == 0) || (buffer.header.name[0] == 0) )
323 sprintf( fname, "%s/%s", prefix, buffer.header.name );
325 /* Check magic value in header */
326 if( strncmp( buffer.header.magic, "GNUtar", 6 ) &&
327 strncmp( buffer.header.magic, "ustar", 5 ) )
329 //fprintf(stderr, "not a tar file\n");
333 switch( buffer.header.typeflag )
340 remaining = getoct( buffer.header.size, 12 );
343 outfile = fopen( fname, "wb" );
344 if( outfile == NULL )
346 /* try creating directory */
347 char *p = strrchr( fname, '/' );
353 outfile = fopen( fname, "wb" );
356 fprintf( stderr, "tar couldn't create %s\n",
365 * could have no contents
367 getheader = (remaining) ? 0 : 1;
375 unsigned int bytes = (remaining > BLOCKSIZE)?BLOCKSIZE:remaining;
377 if( outfile != NULL )
379 if( fwrite( &buffer, sizeof(char), bytes, outfile ) != bytes )
381 fprintf( stderr, "error writing %s skipping...\n", fname );
390 if( outfile != NULL )
403 int tar_close( TAR *t )
405 if( gzclose( *t ) != Z_OK ) fprintf( stderr, "failed gzclose\n" );
411 /* helper functions */
412 int getoct( char *p, int width )
424 result = result * 8 + (c - '0');
430 /* Recursive make directory
431 * Abort if you get an ENOENT errno somewhere in the middle
432 * e.g. ignore error "mkdir on existing directory"
434 * return 1 if OK, 0 on error
436 int makedir( char *newdir )
438 char *p, *buffer = strdup( newdir );
439 int len = strlen( buffer );
447 if( buffer[len-1] == '/' )
449 buffer[len-1] = '\0';
452 if( mkdir( buffer, 0775 ) == 0 )
463 while( *p && *p != '\\' && *p != '/' ) p++;
466 if( ( mkdir( buffer, 0775 ) == -1 ) && ( errno == ENOENT ) )
468 fprintf( stderr, "couldn't create directory %s\n", buffer );
472 if( hold == 0 ) break;
481 int gzopen_frontend( char *pathname, int oflags, int mode )
486 switch( oflags & O_ACCMODE )
500 gzf = gzopen( pathname, gzflags );