1 /*****************************************************************************
2 * themeloader.cpp: ThemeLoader class
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: themeloader.cpp,v 1.14 2003/06/09 12:33:16 asmax 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 msg_Err( p_intf, "%s doesn't contain a " DEFAULT_XML_FILE " file",
161 DeleteTempFiles( TempPath );
165 DeleteTempFiles( TempPath );
168 //---------------------------------------------------------------------------
169 void ThemeLoader::DeleteTempFiles( const string Path )
174 //---------------------------------------------------------------------------
175 void ThemeLoader::CleanTheme()
177 delete (OSTheme *)p_intf->p_sys->p_theme;
178 p_intf->p_sys->p_theme = (Theme *)new OSTheme( p_intf );
180 //---------------------------------------------------------------------------
181 bool ThemeLoader::Parse( const string XmlFile )
183 // Things to do before loading theme
184 p_intf->p_sys->p_theme->OnLoadTheme();
186 // Set the file to parse
187 yyin = fopen( XmlFile.c_str(), "r" );
190 // Skin cannot be opened
191 msg_Warn( p_intf, "Cannot open the specified skin file: %s",
197 msg_Dbg( p_intf, "Using skin file: %s", XmlFile.c_str() );
199 // Save current working directory
200 char *cwd = new char[PATH_MAX];
201 getcwd( cwd, PATH_MAX );
203 // Directory separator is different in each OS !
204 int p = XmlFile.rfind( DIRECTORY_SEPARATOR, XmlFile.size() );
206 // Change current working directory to xml file
209 path = XmlFile.substr( 0, p );
210 chdir( path.c_str() );
212 p_intf->p_sys->b_all_win_closed = false;
220 // Set old working directory to current
224 msg_Warn( p_intf, "yylex failed: %i", lex );
229 // Set old working directory to current
235 //---------------------------------------------------------------------------
236 bool ThemeLoader::Load( const string FileName )
238 // First, we try to un-targz the file, and if it fails we hope it's a XML
240 #if defined( HAVE_ZLIB_H )
241 if( ! Extract( FileName ) && ! Parse( FileName ) )
244 if( ! Parse( FileName ) )
248 // Check if the skin to load is in the config file, to load its config
249 char *skin_last = config_GetPsz( p_intf, "skin_last" );
250 if( skin_last != NULL && FileName == (string)skin_last )
252 p_intf->p_sys->p_theme->LoadConfig();
256 config_PutPsz( p_intf, "skin_last", FileName.c_str() );
257 config_SaveConfigFile( p_intf, "skins" );
262 //---------------------------------------------------------------------------
263 #if !defined( HAVE_LIBTAR_H ) && defined( HAVE_ZLIB_H )
266 # define mkdir(dirname,mode) _mkdir(dirname)
269 /* Values used in typeflag field. */
270 #define REGTYPE '0' /* regular file */
271 #define AREGTYPE '\0' /* regular file */
272 #define DIRTYPE '5' /* directory */
274 #define BLOCKSIZE 512
278 char name[100]; /* 0 */
279 char mode[8]; /* 100 */
280 char uid[8]; /* 108 */
281 char gid[8]; /* 116 */
282 char size[12]; /* 124 */
283 char mtime[12]; /* 136 */
284 char chksum[8]; /* 148 */
285 char typeflag; /* 156 */
286 char linkname[100]; /* 157 */
287 char magic[6]; /* 257 */
288 char version[2]; /* 263 */
289 char uname[32]; /* 265 */
290 char gname[32]; /* 297 */
291 char devmajor[8]; /* 329 */
292 char devminor[8]; /* 337 */
293 char prefix[155]; /* 345 */
298 char buffer[BLOCKSIZE];
299 struct tar_header header;
302 /* helper functions */
303 int getoct( char *p, int width );
304 int makedir( char *newdir );
306 int tar_open( TAR **t, char *pathname, int oflags )
308 gzFile f = gzopen( pathname, "rb" );
311 fprintf( stderr, "Couldn't gzopen %s\n", pathname );
315 *t = (gzFile *)malloc( sizeof(gzFile) );
320 int tar_extract_all( TAR *t, char *prefix )
322 union tar_buffer buffer;
323 int len, err, getheader = 1, remaining = 0;
324 FILE *outfile = NULL;
325 char fname[BLOCKSIZE + PATH_MAX];
329 len = gzread( *t, &buffer, BLOCKSIZE );
330 if(len < 0) fprintf(stderr, "%s", gzerror(*t, &err) );
333 * Always expect complete blocks to process
334 * the tar information.
336 if( len != 0 && len != BLOCKSIZE )
338 fprintf(stderr, "gzread: incomplete block read");
343 * If we have to get a tar header
348 * if we met the end of the tar
349 * or the end-of-tar block,
352 if( (len == 0) || (buffer.header.name[0]== 0) ) break;
354 sprintf( fname, "%s/%s", prefix, buffer.header.name );
356 switch (buffer.header.typeflag)
363 remaining = getoct( buffer.header.size, 12 );
366 outfile = fopen( fname, "wb" );
367 if( outfile == NULL )
369 /* try creating directory */
370 char *p = strrchr( fname, '/' );
376 outfile = fopen( fname, "wb" );
378 fprintf( stderr, "tar couldn't create %s",
386 * could have no contents
388 getheader = (remaining) ? 0 : 1;
396 unsigned int bytes = (remaining > BLOCKSIZE)?BLOCKSIZE:remaining;
398 if( outfile != NULL )
400 if( fwrite( &buffer, sizeof(char), bytes, outfile ) != bytes )
402 fprintf( stderr, "error writing %s skipping...\n", fname );
411 if( outfile != NULL )
423 int tar_close( TAR *t )
425 if( gzclose( *t ) != Z_OK ) fprintf( stderr, "failed gzclose" );
430 /* helper functions */
431 int getoct( char *p, int width )
439 if (c == ' ') continue;
441 result = result * 8 + (c - '0');
446 /* Recursive make directory
447 * Abort if you get an ENOENT errno somewhere in the middle
448 * e.g. ignore error "mkdir on existing directory"
450 * return 1 if OK, 0 on error
452 int makedir( char *newdir )
454 char *p, *buffer = strdup(newdir);
455 int len = strlen(buffer);
457 if( len <= 0 ) { free(buffer); return 0; }
459 if( buffer[len-1] == '/' ) buffer[len-1] = '\0';
461 if( mkdir( buffer, 0775 ) == 0 ) { free(buffer); return 1; }
468 while( *p && *p != '\\' && *p != '/' ) p++;
471 if( ( mkdir( buffer, 0775 ) == -1 ) && ( errno == ENOENT ) )
473 fprintf(stderr,"couldn't create directory %s\n", buffer);
477 if( hold == 0 ) break;
485 //---------------------------------------------------------------------------