1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: theme_loader.cpp,v 1.5 2004/01/24 13:08:12 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 "../parser/xmlparser.hpp"
30 #include "../src/os_factory.hpp"
31 #include "../src/window_manager.hpp"
41 #if defined( HAVE_ZLIB_H )
44 int gzopen_frontend( char *pathname, int oflags, int mode );
45 #if defined( HAVE_LIBTAR_H )
49 int tar_open ( TAR **t, char *pathname, int oflags );
50 int tar_extract_all ( TAR *t, char *prefix );
51 int tar_close ( TAR *t );
55 #define DEFAULT_XML_FILE "theme.xml"
60 int yylex( void *pContext );
61 void yyrestart( FILE *input_file );
64 bool ThemeLoader::load( const string &fileName )
66 // First, we try to un-targz the file, and if it fails we hope it's a XML
68 #if defined( HAVE_ZLIB_H )
69 if( ! extract( fileName ) && ! parse( fileName ) )
72 if( ! parse( fileName ) )
77 // Check if the skin to load is in the config file, to load its config
78 char *skin_last = config_GetPsz( getIntf(), "skin_last" );
79 if( skin_last != NULL && fileName == (string)skin_last )
81 getIntf()->p_sys->p_theme->LoadConfig();
85 config_PutPsz( getIntf(), "skin_last", fileName.c_str() );
86 config_SaveConfigFile( getIntf(), "skins" );
89 Theme *pNewTheme = getIntf()->p_sys->p_theme;
92 // Used to anchor the windows at the beginning
93 pNewTheme->getWindowManager().stopMove();
95 pNewTheme->getWindowManager().showAll();
102 #if defined( HAVE_ZLIB_H )
103 bool ThemeLoader::extractTarGz( const string &tarFile, const string &rootDir )
106 #if defined( HAVE_LIBTAR_H )
107 tartype_t gztype = { (openfunc_t) gzopen_frontend, (closefunc_t) gzclose,
108 (readfunc_t) gzread, (writefunc_t) gzwrite };
110 if( tar_open( &t, (char *)tarFile.c_str(), &gztype, O_RDONLY, 0,
113 if( tar_open( &t, (char *)tarFile.c_str(), O_RDONLY ) == -1 )
119 if( tar_extract_all( t, (char *)rootDir.c_str() ) != 0 )
125 if( tar_close( t ) != 0 )
134 bool ThemeLoader::extract( const string &fileName )
136 char *tmpdir = tempnam( NULL, "vlt" );
137 string tempPath = tmpdir;
140 // Extract the file in a temporary directory
141 if( ! extractTarGz( fileName, tempPath ) )
144 // Parse the extracted XML file
145 const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
146 if( ! parse( tempPath + sep + string( DEFAULT_XML_FILE ) ) )
148 msg_Err( getIntf(), "%s doesn't contain a " DEFAULT_XML_FILE " file",
150 deleteTempFiles( tempPath );
155 deleteTempFiles( tempPath );
160 void ThemeLoader::deleteTempFiles( const string &path )
162 OSFactory::instance( getIntf() )->rmDir( path );
164 #endif // HAVE_ZLIB_H
167 bool ThemeLoader::parse( const string &xmlFile )
169 // Set the file to parse
170 FILE *file = fopen( xmlFile.c_str(), "r" );
173 // Skin cannot be opened
174 msg_Err( getIntf(), "Cannot open the specified skin file: %s",
181 msg_Dbg( getIntf(), "Using skin file: %s", xmlFile.c_str() );
183 // Save current working directory
184 char *cwd = new char[PATH_MAX];
185 getcwd( cwd, PATH_MAX );
187 // Change current working directory to xml file
188 const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
189 unsigned int p = xmlFile.rfind( sep, xmlFile.size() );
190 if( p != string::npos )
192 string path = xmlFile.substr( 0, p );
193 chdir( path.c_str() );
197 ParserContext context( getIntf() );
198 int lex = yylex( &context );
203 // Set old working directory to current
207 msg_Warn( getIntf(), "yylex failed: %i", lex );
211 XMLParser parser( getIntf(), xmlFile );
214 // Build and store the theme
215 Builder builder( getIntf(), context.m_data );
216 getIntf()->p_sys->p_theme = builder.build();
218 // Set old working directory to current.
219 // We need to do that _after_ calling Builder:build(), otherwise the
220 // opening of the files will fail
228 #if !defined( HAVE_LIBTAR_H ) && defined( HAVE_ZLIB_H )
231 # define mkdir(dirname,mode) _mkdir(dirname)
234 /* Values used in typeflag field */
235 #define REGTYPE '0' /* regular file */
236 #define AREGTYPE '\0' /* regular file */
237 #define DIRTYPE '5' /* directory */
239 #define BLOCKSIZE 512
243 char name[100]; /* 0 */
244 char mode[8]; /* 100 */
245 char uid[8]; /* 108 */
246 char gid[8]; /* 116 */
247 char size[12]; /* 124 */
248 char mtime[12]; /* 136 */
249 char chksum[8]; /* 148 */
250 char typeflag; /* 156 */
251 char linkname[100]; /* 157 */
252 char magic[6]; /* 257 */
253 char version[2]; /* 263 */
254 char uname[32]; /* 265 */
255 char gname[32]; /* 297 */
256 char devmajor[8]; /* 329 */
257 char devminor[8]; /* 337 */
258 char prefix[155]; /* 345 */
264 char buffer[BLOCKSIZE];
265 struct tar_header header;
269 /* helper functions */
270 int getoct( char *p, int width );
271 int makedir( char *newdir );
273 int tar_open( TAR **t, char *pathname, int oflags )
275 gzFile f = gzopen( pathname, "rb" );
278 fprintf( stderr, "Couldn't gzopen %s\n", pathname );
282 *t = (gzFile *)malloc( sizeof(gzFile) );
288 int tar_extract_all( TAR *t, char *prefix )
290 union tar_buffer buffer;
291 int len, err, getheader = 1, remaining = 0;
292 FILE *outfile = NULL;
293 char fname[BLOCKSIZE + PATH_MAX];
297 len = gzread( *t, &buffer, BLOCKSIZE );
300 fprintf( stderr, "%s\n", gzerror(*t, &err) );
304 * Always expect complete blocks to process
305 * the tar information.
307 if( len != 0 && len != BLOCKSIZE )
309 fprintf( stderr, "gzread: incomplete block read\n" );
314 * If we have to get a tar header
319 * If we met the end of the tar
320 * or the end-of-tar block, we are done
322 if( (len == 0) || (buffer.header.name[0] == 0) )
327 sprintf( fname, "%s/%s", prefix, buffer.header.name );
329 /* Check magic value in header */
330 if( strncmp( buffer.header.magic, "GNUtar", 6 ) &&
331 strncmp( buffer.header.magic, "ustar", 5 ) )
333 //fprintf(stderr, "not a tar file\n");
337 switch( buffer.header.typeflag )
344 remaining = getoct( buffer.header.size, 12 );
347 outfile = fopen( fname, "wb" );
348 if( outfile == NULL )
350 /* try creating directory */
351 char *p = strrchr( fname, '/' );
357 outfile = fopen( fname, "wb" );
360 fprintf( stderr, "tar couldn't create %s\n",
369 * could have no contents
371 getheader = (remaining) ? 0 : 1;
379 unsigned int bytes = (remaining > BLOCKSIZE)?BLOCKSIZE:remaining;
381 if( outfile != NULL )
383 if( fwrite( &buffer, sizeof(char), bytes, outfile ) != bytes )
385 fprintf( stderr, "error writing %s skipping...\n", fname );
394 if( outfile != NULL )
407 int tar_close( TAR *t )
409 if( gzclose( *t ) != Z_OK ) fprintf( stderr, "failed gzclose\n" );
415 /* helper functions */
416 int getoct( char *p, int width )
428 result = result * 8 + (c - '0');
434 /* Recursive make directory
435 * Abort if you get an ENOENT errno somewhere in the middle
436 * e.g. ignore error "mkdir on existing directory"
438 * return 1 if OK, 0 on error
440 int makedir( char *newdir )
442 char *p, *buffer = strdup( newdir );
443 int len = strlen( buffer );
451 if( buffer[len-1] == '/' )
453 buffer[len-1] = '\0';
456 if( mkdir( buffer, 0775 ) == 0 )
467 while( *p && *p != '\\' && *p != '/' ) p++;
470 if( ( mkdir( buffer, 0775 ) == -1 ) && ( errno == ENOENT ) )
472 fprintf( stderr, "couldn't create directory %s\n", buffer );
476 if( hold == 0 ) break;
485 int gzopen_frontend( char *pathname, int oflags, int mode )
490 switch( oflags & O_ACCMODE )
504 gzf = gzopen( pathname, gzflags );