00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "theme_loader.hpp"
00026 #include "theme.hpp"
00027 #include "../parser/builder.hpp"
00028 #include "../parser/skin_parser.hpp"
00029 #include "../src/os_factory.hpp"
00030 #include "../src/vlcproc.hpp"
00031 #include "../src/window_manager.hpp"
00032
00033 #ifdef HAVE_FCNTL_H
00034 # include <fcntl.h>
00035 #endif
00036 #ifdef HAVE_SYS_STAT_H
00037 # include <sys/stat.h>
00038 #endif
00039 #ifdef HAVE_UNISTD_H
00040 # include <unistd.h>
00041 #elif defined( WIN32 ) && !defined( UNDER_CE )
00042 # include <direct.h>
00043 #endif
00044
00045 #ifdef HAVE_DIRENT_H
00046 # include <dirent.h>
00047 #endif
00048
00049
00050 #if defined( HAVE_ZLIB_H )
00051 # include <zlib.h>
00052 # include <errno.h>
00053 int gzopen_frontend ( char *pathname, int oflags, int mode );
00054 int gzclose_frontend( int );
00055 int gzread_frontend ( int, void *, size_t );
00056 int gzwrite_frontend( int, const void *, size_t );
00057 #if defined( HAVE_LIBTAR_H )
00058 # include <libtar.h>
00059 #else
00060 typedef gzFile TAR;
00061 int tar_open ( TAR **t, char *pathname, int oflags );
00062 int tar_extract_all ( TAR *t, char *prefix );
00063 int tar_close ( TAR *t );
00064 #endif
00065 #endif
00066
00067 #define DEFAULT_XML_FILE "theme.xml"
00068
00069
00070 bool ThemeLoader::load( const string &fileName )
00071 {
00072
00073
00074 #if defined( HAVE_ZLIB_H )
00075 if( ! extract( fileName ) && ! parse( fileName ) )
00076 return false;
00077 #else
00078 if( ! parse( fileName ) )
00079 return false;
00080 #endif
00081
00082 Theme *pNewTheme = getIntf()->p_sys->p_theme;
00083 if( !pNewTheme )
00084 {
00085 return false;
00086 }
00087
00088
00089 char *skin_last = config_GetPsz( getIntf(), "skins2-last" );
00090 if( skin_last != NULL && fileName == (string)skin_last )
00091 {
00092
00093 getIntf()->p_sys->p_theme->loadConfig();
00094
00095 pNewTheme->getWindowManager().stopMove();
00096 }
00097 else
00098 {
00099 config_PutPsz( getIntf(), "skins2-last", fileName.c_str() );
00100
00101 pNewTheme->getWindowManager().showAll( true );
00102 }
00103 if( skin_last ) free( skin_last );
00104
00105
00106 VlcProc::instance( getIntf() )->dropVout();
00107
00108 return true;
00109 }
00110
00111
00112 #if defined( HAVE_ZLIB_H )
00113 bool ThemeLoader::extractTarGz( const string &tarFile, const string &rootDir )
00114 {
00115 TAR *t;
00116 #if defined( HAVE_LIBTAR_H )
00117 tartype_t gztype = { (openfunc_t) gzopen_frontend,
00118 (closefunc_t) gzclose_frontend,
00119 (readfunc_t) gzread_frontend,
00120 (writefunc_t) gzwrite_frontend };
00121
00122 if( tar_open( &t, (char *)tarFile.c_str(), &gztype, O_RDONLY, 0,
00123 TAR_GNU ) == -1 )
00124 #else
00125 if( tar_open( &t, (char *)tarFile.c_str(), O_RDONLY ) == -1 )
00126 #endif
00127 {
00128 return false;
00129 }
00130
00131 if( tar_extract_all( t, (char *)rootDir.c_str() ) != 0 )
00132 {
00133 tar_close( t );
00134 return false;
00135 }
00136
00137 if( tar_close( t ) != 0 )
00138 {
00139 return false;
00140 }
00141
00142 return true;
00143 }
00144
00145
00146 bool ThemeLoader::extract( const string &fileName )
00147 {
00148 char *tmpdir = tempnam( NULL, "vlt" );
00149 string tempPath = tmpdir;
00150 free( tmpdir );
00151
00152
00153 if( ! extractTarGz( fileName, tempPath ) )
00154 return false;
00155
00156
00157 string xmlFile;
00158 if( ! findThemeFile( tempPath, xmlFile ) || ! parse( xmlFile ) )
00159 {
00160 msg_Err( getIntf(), "%s doesn't contain a " DEFAULT_XML_FILE " file",
00161 fileName.c_str() );
00162 deleteTempFiles( tempPath );
00163 return false;
00164 }
00165
00166
00167 deleteTempFiles( tempPath );
00168 return true;
00169 }
00170
00171
00172 void ThemeLoader::deleteTempFiles( const string &path )
00173 {
00174 OSFactory::instance( getIntf() )->rmDir( path );
00175 }
00176 #endif // HAVE_ZLIB_H
00177
00178
00179 bool ThemeLoader::parse( const string &xmlFile )
00180 {
00181
00182 msg_Dbg( getIntf(), "Using skin file: %s", xmlFile.c_str() );
00183
00184
00185 string path;
00186 const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
00187 string::size_type p = xmlFile.rfind( sep, xmlFile.size() );
00188 if( p != string::npos )
00189 {
00190 path = xmlFile.substr( 0, p + 1 );
00191 }
00192 else
00193 {
00194 path = "";
00195 }
00196
00197
00198 SkinParser parser( getIntf(), xmlFile, path );
00199 if( ! parser.parse() )
00200 {
00201 msg_Err( getIntf(), "Failed to parse %s", xmlFile.c_str() );
00202 return false;
00203 }
00204
00205
00206 Builder builder( getIntf(), parser.getData() );
00207 getIntf()->p_sys->p_theme = builder.build();
00208
00209 return true;
00210 }
00211
00212
00213 bool ThemeLoader::findThemeFile( const string &rootDir, string &themeFilePath )
00214 {
00215
00216 const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
00217
00218 DIR *pCurrDir;
00219 struct dirent *pDirContent;
00220
00221
00222 pCurrDir = opendir( rootDir.c_str() );
00223
00224 if( pCurrDir == NULL )
00225 {
00226
00227 msg_Dbg( getIntf(), "Cannot open directory %s", rootDir.c_str() );
00228 return false;
00229 }
00230
00231
00232 pDirContent = (dirent*)readdir( pCurrDir );
00233
00234
00235 while( pDirContent != NULL )
00236 {
00237 string newURI = rootDir + sep + pDirContent->d_name;
00238
00239
00240 if( string( pDirContent->d_name ) != "." &&
00241 string( pDirContent->d_name ) != ".." )
00242 {
00243 #if defined( S_ISDIR )
00244 struct stat stat_data;
00245 stat( newURI.c_str(), &stat_data );
00246 if( S_ISDIR(stat_data.st_mode) )
00247 #elif defined( DT_DIR )
00248 if( pDirContent->d_type & DT_DIR )
00249 #else
00250 if( 0 )
00251 #endif
00252 {
00253
00254 if( findThemeFile( newURI, themeFilePath ) )
00255 {
00256 closedir( pCurrDir );
00257 return true;
00258 }
00259 }
00260 else
00261 {
00262
00263 if( string( DEFAULT_XML_FILE ) ==
00264 string( pDirContent->d_name ) )
00265 {
00266 themeFilePath = newURI;
00267 closedir( pCurrDir );
00268 return true;
00269 }
00270 }
00271 }
00272
00273 pDirContent = (dirent*)readdir( pCurrDir );
00274 }
00275
00276 closedir( pCurrDir );
00277 return false;
00278 }
00279
00280
00281 #if !defined( HAVE_LIBTAR_H ) && defined( HAVE_ZLIB_H )
00282
00283 #ifdef WIN32
00284 # define mkdir(dirname,mode) _mkdir(dirname)
00285 #endif
00286
00287
00288 #define REGTYPE '0'
00289 #define AREGTYPE '\0'
00290 #define DIRTYPE '5'
00291
00292 #define BLOCKSIZE 512
00293
00294 struct tar_header
00295 {
00296 char name[100];
00297 char mode[8];
00298 char uid[8];
00299 char gid[8];
00300 char size[12];
00301 char mtime[12];
00302 char chksum[8];
00303 char typeflag;
00304 char linkname[100];
00305 char magic[6];
00306 char version[2];
00307 char uname[32];
00308 char gname[32];
00309 char devmajor[8];
00310 char devminor[8];
00311 char prefix[155];
00312
00313 };
00314
00315
00316 union tar_buffer {
00317 char buffer[BLOCKSIZE];
00318 struct tar_header header;
00319 };
00320
00321
00322
00323 int getoct( char *p, int width );
00324 int makedir( char *newdir );
00325
00326 int tar_open( TAR **t, char *pathname, int oflags )
00327 {
00328 gzFile f = gzopen( pathname, "rb" );
00329 if( f == NULL )
00330 {
00331 fprintf( stderr, "Couldn't gzopen %s\n", pathname );
00332 return -1;
00333 }
00334
00335 *t = (gzFile *)malloc( sizeof(gzFile) );
00336 **t = f;
00337 return 0;
00338 }
00339
00340
00341 int tar_extract_all( TAR *t, char *prefix )
00342 {
00343 union tar_buffer buffer;
00344 int len, err, getheader = 1, remaining = 0;
00345 FILE *outfile = NULL;
00346 char fname[BLOCKSIZE + PATH_MAX];
00347
00348 while( 1 )
00349 {
00350 len = gzread( *t, &buffer, BLOCKSIZE );
00351 if( len < 0 )
00352 {
00353 fprintf( stderr, "%s\n", gzerror(*t, &err) );
00354 }
00355
00356
00357
00358
00359
00360 if( len != 0 && len != BLOCKSIZE )
00361 {
00362 fprintf( stderr, "gzread: incomplete block read\n" );
00363 return -1;
00364 }
00365
00366
00367
00368
00369 if( getheader == 1 )
00370 {
00371
00372
00373
00374
00375 if( (len == 0) || (buffer.header.name[0] == 0) )
00376 {
00377 break;
00378 }
00379
00380 sprintf( fname, "%s/%s", prefix, buffer.header.name );
00381
00382
00383 if( strncmp( buffer.header.magic, "GNUtar", 6 ) &&
00384 strncmp( buffer.header.magic, "ustar", 5 ) )
00385 {
00386
00387 return -1;
00388 }
00389
00390 switch( buffer.header.typeflag )
00391 {
00392 case DIRTYPE:
00393 makedir( fname );
00394 break;
00395 case REGTYPE:
00396 case AREGTYPE:
00397 remaining = getoct( buffer.header.size, 12 );
00398 if( remaining )
00399 {
00400 outfile = fopen( fname, "wb" );
00401 if( outfile == NULL )
00402 {
00403
00404 char *p = strrchr( fname, '/' );
00405 if( p != NULL )
00406 {
00407 *p = '\0';
00408 makedir( fname );
00409 *p = '/';
00410 outfile = fopen( fname, "wb" );
00411 if( !outfile )
00412 {
00413 fprintf( stderr, "tar couldn't create %s\n",
00414 fname );
00415 }
00416 }
00417 }
00418 }
00419 else outfile = NULL;
00420
00421
00422
00423
00424 getheader = (remaining) ? 0 : 1;
00425 break;
00426 default:
00427 break;
00428 }
00429 }
00430 else
00431 {
00432 unsigned int bytes = (remaining > BLOCKSIZE)?BLOCKSIZE:remaining;
00433
00434 if( outfile != NULL )
00435 {
00436 if( fwrite( &buffer, sizeof(char), bytes, outfile ) != bytes )
00437 {
00438 fprintf( stderr, "error writing %s skipping...\n", fname );
00439 fclose( outfile );
00440 unlink( fname );
00441 }
00442 }
00443 remaining -= bytes;
00444 if( remaining == 0 )
00445 {
00446 getheader = 1;
00447 if( outfile != NULL )
00448 {
00449 fclose(outfile);
00450 outfile = NULL;
00451 }
00452 }
00453 }
00454 }
00455
00456 return 0;
00457 }
00458
00459
00460 int tar_close( TAR *t )
00461 {
00462 if( gzclose( *t ) != Z_OK ) fprintf( stderr, "failed gzclose\n" );
00463 free( t );
00464 return 0;
00465 }
00466
00467
00468
00469 int getoct( char *p, int width )
00470 {
00471 int result = 0;
00472 char c;
00473
00474 while( width-- )
00475 {
00476 c = *p++;
00477 if( c == ' ' )
00478 continue;
00479 if( c == 0 )
00480 break;
00481 result = result * 8 + (c - '0');
00482 }
00483 return result;
00484 }
00485
00486
00487
00488
00489
00490
00491
00492
00493 int makedir( char *newdir )
00494 {
00495 char *p, *buffer = strdup( newdir );
00496 int len = strlen( buffer );
00497
00498 if( len <= 0 )
00499 {
00500 free( buffer );
00501 return 0;
00502 }
00503
00504 if( buffer[len-1] == '/' )
00505 {
00506 buffer[len-1] = '\0';
00507 }
00508
00509 if( mkdir( buffer, 0775 ) == 0 )
00510 {
00511 free( buffer );
00512 return 1;
00513 }
00514
00515 p = buffer + 1;
00516 while( 1 )
00517 {
00518 char hold;
00519
00520 while( *p && *p != '\\' && *p != '/' ) p++;
00521 hold = *p;
00522 *p = 0;
00523 if( ( mkdir( buffer, 0775 ) == -1 ) && ( errno == ENOENT ) )
00524 {
00525 fprintf( stderr, "couldn't create directory %s\n", buffer );
00526 free( buffer );
00527 return 0;
00528 }
00529 if( hold == 0 ) break;
00530 *p++ = hold;
00531 }
00532 free( buffer );
00533 return 1;
00534 }
00535 #endif
00536
00537 #ifdef HAVE_ZLIB_H
00538
00539 static int currentGzFd = -1;
00540 static void * currentGzVp = NULL;
00541
00542 int gzopen_frontend( char *pathname, int oflags, int mode )
00543 {
00544 char *gzflags;
00545 gzFile gzf;
00546
00547 switch( oflags )
00548 {
00549 case O_WRONLY:
00550 gzflags = "wb";
00551 break;
00552 case O_RDONLY:
00553 gzflags = "rb";
00554 break;
00555 case O_RDWR:
00556 default:
00557 errno = EINVAL;
00558 return -1;
00559 }
00560
00561 gzf = gzopen( pathname, gzflags );
00562 if( !gzf )
00563 {
00564 errno = ENOMEM;
00565 return -1;
00566 }
00567
00569 currentGzFd = 42;
00570 currentGzVp = gzf;
00571
00572 return currentGzFd;
00573 }
00574
00575 int gzclose_frontend( int fd )
00576 {
00577 if( currentGzVp != NULL && fd != -1 )
00578 {
00579 void *toClose = currentGzVp;
00580 currentGzVp = NULL; currentGzFd = -1;
00581 return gzclose( toClose );
00582 }
00583 return -1;
00584 }
00585
00586 int gzread_frontend( int fd, void *p_buffer, size_t i_length )
00587 {
00588 if( currentGzVp != NULL && fd != -1 )
00589 {
00590 return gzread( currentGzVp, p_buffer, i_length );
00591 }
00592 return -1;
00593 }
00594
00595 int gzwrite_frontend( int fd, const void * p_buffer, size_t i_length )
00596 {
00597 if( currentGzVp != NULL && fd != -1 )
00598 {
00599 return gzwrite( currentGzVp, const_cast<void*>(p_buffer), i_length );
00600 }
00601 return -1;
00602 }
00603
00604 #endif