1 /*****************************************************************************
2 * themeloader.cpp: ThemeLoader class
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: themeloader.cpp,v 1.9 2003/05/02 15:53:32 gbazin Exp $
7 * Authors: Olivier Teulière <ipkiss@via.ecp.fr>
8 * Emmanuel Puig <karibu@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,
24 *****************************************************************************/
27 //--- GENERAL ---------------------------------------------------------------
35 # define PATH_MAX MAX_PATH
39 //--- VLC -------------------------------------------------------------------
43 #if defined( HAVE_ZLIB_H )
48 #if defined( HAVE_ZLIB_H ) && defined( HAVE_LIBTAR_H )
50 #elif defined( HAVE_ZLIB_H )
52 int tar_open ( TAR **t, char *pathname, int oflags );
53 int tar_extract_all ( TAR *t, char *prefix );
54 int tar_close ( TAR *t );
57 //--- SKIN ------------------------------------------------------------------
58 #include "../os_api.h"
60 #include "../os_theme.h"
61 #include "themeloader.h"
62 #include "skin_common.h"
67 #define DEFAULT_XML_FILE "theme.xml"
69 //---------------------------------------------------------------------------
76 //---------------------------------------------------------------------------
77 ThemeLoader::ThemeLoader( intf_thread_t *_p_intf )
81 //---------------------------------------------------------------------------
82 ThemeLoader::~ThemeLoader()
85 //---------------------------------------------------------------------------
86 #if defined( HAVE_ZLIB_H )
87 int gzopen_frontend( char *pathname, int oflags, int mode )
92 switch( oflags & O_ACCMODE )
106 gzf = gzopen( pathname, gzflags );
117 //---------------------------------------------------------------------------
118 #if defined( HAVE_ZLIB_H )
119 bool ThemeLoader::ExtractTarGz( const string tarfile, const string rootdir )
122 #if defined( HAVE_LIBTAR_H )
123 tartype_t gztype = { (openfunc_t) gzopen_frontend, (closefunc_t) gzclose,
124 (readfunc_t) gzread, (writefunc_t) gzwrite };
126 if( tar_open( &t, (char *)tarfile.c_str(), &gztype, O_RDONLY, 0,
129 if( tar_open( &t, (char *)tarfile.c_str(), O_RDONLY ) == -1 )
135 if( tar_extract_all( t, (char *)rootdir.c_str() ) != 0 )
140 if( tar_close( t ) != 0 )
147 //---------------------------------------------------------------------------
148 bool ThemeLoader::Extract( const string FileName )
150 char *tmpdir = tempnam( NULL, "vlt" );
151 string TempPath = tmpdir;
154 if( ! ExtractTarGz( FileName, TempPath ) )
157 if( ! Parse( TempPath + DIRECTORY_SEPARATOR + string( DEFAULT_XML_FILE ) ) )
159 DeleteTempFiles( TempPath );
163 DeleteTempFiles( TempPath );
166 //---------------------------------------------------------------------------
167 void ThemeLoader::DeleteTempFiles( const string Path )
172 //---------------------------------------------------------------------------
173 void ThemeLoader::CleanTheme()
175 delete (OSTheme *)p_intf->p_sys->p_theme;
176 p_intf->p_sys->p_theme = (Theme *)new OSTheme( p_intf );
178 //---------------------------------------------------------------------------
179 bool ThemeLoader::Parse( const string XmlFile )
181 // Things to do before loading theme
182 p_intf->p_sys->p_theme->OnLoadTheme();
184 // Set the file to parse
185 yyin = fopen( XmlFile.c_str(), "r" );
188 // Skin cannot be opened
189 msg_Warn( p_intf, "Cannot open the specified skin file: %s",
195 msg_Dbg( p_intf, "Using skin file: %s", XmlFile.c_str() );
197 // Save current working directory
198 char *cwd = new char[PATH_MAX];
199 getcwd( cwd, PATH_MAX );
201 // Directory separator is different in each OS !
202 int p = XmlFile.rfind( DIRECTORY_SEPARATOR, XmlFile.size() );
204 // Change current working directory to xml file
207 path = XmlFile.substr( 0, p );
208 chdir( path.c_str() );
210 p_intf->p_sys->b_all_win_closed = false;
218 // Set old working directory to current
222 msg_Warn( p_intf, "yylex failed: %i", lex );
227 // Set old working directory to current
233 //---------------------------------------------------------------------------
234 bool ThemeLoader::Load( const string FileName )
236 // First, we try to un-targz the file, and if it fails we hope it's a XML
238 #if defined( HAVE_ZLIB_H )
239 if( ! Extract( FileName ) && ! Parse( FileName ) )
242 if( ! Parse( FileName ) )
246 // Check if the skin to load is in the config file, to load its config
247 char *skin_last = config_GetPsz( p_intf, "skin_last" );
248 if( skin_last != NULL && FileName == (string)skin_last )
250 p_intf->p_sys->p_theme->LoadConfig();
254 config_PutPsz( p_intf, "skin_last", FileName.c_str() );
255 config_SaveConfigFile( p_intf, "skins" );
260 //---------------------------------------------------------------------------
261 #if !defined( HAVE_LIBTAR_H ) && defined( HAVE_ZLIB_H )
264 # define mkdir(dirname,mode) _mkdir(dirname)
267 /* Values used in typeflag field. */
268 #define REGTYPE '0' /* regular file */
269 #define AREGTYPE '\0' /* regular file */
270 #define DIRTYPE '5' /* directory */
272 #define BLOCKSIZE 512
276 char name[100]; /* 0 */
277 char mode[8]; /* 100 */
278 char uid[8]; /* 108 */
279 char gid[8]; /* 116 */
280 char size[12]; /* 124 */
281 char mtime[12]; /* 136 */
282 char chksum[8]; /* 148 */
283 char typeflag; /* 156 */
284 char linkname[100]; /* 157 */
285 char magic[6]; /* 257 */
286 char version[2]; /* 263 */
287 char uname[32]; /* 265 */
288 char gname[32]; /* 297 */
289 char devmajor[8]; /* 329 */
290 char devminor[8]; /* 337 */
291 char prefix[155]; /* 345 */
296 char buffer[BLOCKSIZE];
297 struct tar_header header;
300 /* helper functions */
301 int getoct( char *p, int width );
302 int makedir( char *newdir );
304 int tar_open( TAR **t, char *pathname, int oflags )
306 gzFile f = gzopen( pathname, "rb" );
309 fprintf( stderr, "Couldn't gzopen %s\n", pathname );
313 *t = (gzFile *)malloc( sizeof(gzFile) );
318 int tar_extract_all( TAR *t, char *prefix )
320 union tar_buffer buffer;
321 int len, err, getheader = 1, remaining = 0;
322 FILE *outfile = NULL;
323 char fname[BLOCKSIZE + PATH_MAX];
327 len = gzread( *t, &buffer, BLOCKSIZE );
328 if(len < 0) fprintf(stderr, "%s", gzerror(*t, &err) );
331 * Always expect complete blocks to process
332 * the tar information.
334 if(len != BLOCKSIZE) fprintf(stderr, "gzread: incomplete block read");
337 * If we have to get a tar header
342 * if we met the end of the tar
343 * or the end-of-tar block,
346 if( (len == 0) || (buffer.header.name[0]== 0) ) break;
348 sprintf( fname, "%s/%s", prefix, buffer.header.name );
350 switch (buffer.header.typeflag)
357 remaining = getoct( buffer.header.size, 12 );
360 outfile = fopen( fname, "wb" );
361 if( outfile == NULL )
363 /* try creating directory */
364 char *p = strrchr( fname, '/' );
370 outfile = fopen( fname, "wb" );
372 fprintf( stderr, "tar couldn't create %s",
380 * could have no contents
382 getheader = (remaining) ? 0 : 1;
390 unsigned int bytes = (remaining > BLOCKSIZE)?BLOCKSIZE:remaining;
392 if( outfile != NULL )
394 if( fwrite( &buffer, sizeof(char), bytes, outfile ) != bytes )
396 fprintf( stderr, "error writing %s skipping...\n", fname );
405 if( outfile != NULL )
417 int tar_close( TAR *t )
419 if( gzclose( *t ) != Z_OK ) fprintf( stderr, "failed gzclose" );
424 /* helper functions */
425 int getoct( char *p, int width )
433 if (c == ' ') continue;
435 result = result * 8 + (c - '0');
440 /* Recursive make directory
441 * Abort if you get an ENOENT errno somewhere in the middle
442 * e.g. ignore error "mkdir on existing directory"
444 * return 1 if OK, 0 on error
446 int makedir( char *newdir )
448 char *p, *buffer = strdup(newdir);
449 int len = strlen(buffer);
451 if( len <= 0 ) { free(buffer); return 0; }
453 if( buffer[len-1] == '/' ) buffer[len-1] = '\0';
455 if( mkdir( buffer, 0775 ) == 0 ) { free(buffer); return 1; }
462 while( *p && *p != '\\' && *p != '/' ) p++;
465 if( ( mkdir( buffer, 0775 ) == -1 ) && ( errno == ENOENT ) )
467 fprintf(stderr,"couldn't create directory %s\n", buffer);
471 if( hold == 0 ) break;
479 //---------------------------------------------------------------------------