theme_loader.cpp
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:14k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * theme_loader.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 VideoLAN
  5.  * $Id: theme_loader.cpp 7896 2004-06-05 19:23:03Z ipkiss $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teuli鑢e <ipkiss@via.ecp.fr>
  9.  *
  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.
  14.  *
  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.
  19.  *
  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.  *****************************************************************************/
  24. #include "theme_loader.hpp"
  25. #include "theme.hpp"
  26. #include "../parser/builder.hpp"
  27. #include "../parser/skin_parser.hpp"
  28. #include "../src/os_factory.hpp"
  29. #include "../src/window_manager.hpp"
  30. #ifdef HAVE_FCNTL_H
  31. #   include <fcntl.h>
  32. #endif
  33. #ifdef HAVE_SYS_STAT_H
  34. #   include <sys/stat.h>
  35. #endif
  36. #ifdef HAVE_UNISTD_H
  37. #   include <unistd.h>
  38. #elif defined( WIN32 )
  39. #   include <direct.h>
  40. #endif
  41. #if (!defined( WIN32 ) || defined(__MINGW32__))
  42. /* Mingw has its own version of dirent */
  43. #   include <dirent.h>
  44. #endif
  45. #if defined( HAVE_ZLIB_H )
  46. #   include <zlib.h>
  47. #   include <errno.h>
  48. int gzopen_frontend( char *pathname, int oflags, int mode );
  49. #if defined( HAVE_LIBTAR_H )
  50. #   include <libtar.h>
  51. #else
  52. typedef gzFile TAR;
  53. int tar_open        ( TAR **t, char *pathname, int oflags );
  54. int tar_extract_all ( TAR *t, char *prefix );
  55. int tar_close       ( TAR *t );
  56. #endif
  57. #endif
  58. #define DEFAULT_XML_FILE "theme.xml"
  59. bool ThemeLoader::load( const string &fileName )
  60. {
  61.     // First, we try to un-targz the file, and if it fails we hope it's a XML
  62.     // file...
  63. #if defined( HAVE_ZLIB_H )
  64.     if( ! extract( fileName ) && ! parse( fileName ) )
  65.         return false;
  66. #else
  67.     if( ! parse( fileName ) )
  68.         return false;
  69. #endif
  70.     Theme *pNewTheme = getIntf()->p_sys->p_theme;
  71.     if( !pNewTheme )
  72.     {
  73.         return false;
  74.     }
  75.     // Check if the skin to load is in the config file, to load its config
  76.     char *skin_last = config_GetPsz( getIntf(), "skins2-last" );
  77.     if( skin_last != NULL && fileName == (string)skin_last )
  78.     {
  79.         // Restore the theme configuration
  80.         getIntf()->p_sys->p_theme->loadConfig();
  81.         // Used to anchor the windows at the beginning
  82.         pNewTheme->getWindowManager().stopMove();
  83.     }
  84.     else
  85.     {
  86.         config_PutPsz( getIntf(), "skins2-last", fileName.c_str() );
  87.         // Show the windows
  88.         pNewTheme->getWindowManager().showAll();
  89.     }
  90.     return true;
  91. }
  92. #if defined( HAVE_ZLIB_H )
  93. bool ThemeLoader::extractTarGz( const string &tarFile, const string &rootDir )
  94. {
  95.     TAR *t;
  96. #if defined( HAVE_LIBTAR_H )
  97.     tartype_t gztype = { (openfunc_t) gzopen_frontend, (closefunc_t) gzclose,
  98.         (readfunc_t) gzread, (writefunc_t) gzwrite };
  99.     if( tar_open( &t, (char *)tarFile.c_str(), &gztype, O_RDONLY, 0,
  100.                   TAR_GNU ) == -1 )
  101. #else
  102.     if( tar_open( &t, (char *)tarFile.c_str(), O_RDONLY ) == -1 )
  103. #endif
  104.     {
  105.         return false;
  106.     }
  107.     if( tar_extract_all( t, (char *)rootDir.c_str() ) != 0 )
  108.     {
  109.         tar_close( t );
  110.         return false;
  111.     }
  112.     if( tar_close( t ) != 0 )
  113.     {
  114.         return false;
  115.     }
  116.     return true;
  117. }
  118. bool ThemeLoader::extract( const string &fileName )
  119. {
  120.     char *tmpdir = tempnam( NULL, "vlt" );
  121.     string tempPath = tmpdir;
  122.     free( tmpdir );
  123.     // Extract the file in a temporary directory
  124.     if( ! extractTarGz( fileName, tempPath ) )
  125.         return false;
  126.     // Find the XML file and parse it
  127.     string xmlFile;
  128.     if( ! findThemeFile( tempPath, xmlFile ) || ! parse( xmlFile ) )
  129.     {
  130.         msg_Err( getIntf(), "%s doesn't contain a " DEFAULT_XML_FILE " file",
  131.                  fileName.c_str() );
  132.         deleteTempFiles( tempPath );
  133.         return false;
  134.     }
  135.     // Clean-up
  136.     deleteTempFiles( tempPath );
  137.     return true;
  138. }
  139. void ThemeLoader::deleteTempFiles( const string &path )
  140. {
  141.     OSFactory::instance( getIntf() )->rmDir( path );
  142. }
  143. #endif // HAVE_ZLIB_H
  144. bool ThemeLoader::parse( const string &xmlFile )
  145. {
  146.     // File loaded
  147.     msg_Dbg( getIntf(), "Using skin file: %s", xmlFile.c_str() );
  148.     // Extract the path of the XML file
  149.     string path;
  150.     const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
  151.     unsigned int p = xmlFile.rfind( sep, xmlFile.size() );
  152.     if( p != string::npos )
  153.     {
  154.         path = xmlFile.substr( 0, p + 1 );
  155.     }
  156.     else
  157.     {
  158.         path = "";
  159.     }
  160.     // Start the parser
  161.     SkinParser parser( getIntf(), xmlFile, path );
  162.     if( ! parser.parse() )
  163.     {
  164.         msg_Err( getIntf(), "Failed to parse %s", xmlFile.c_str() );
  165.         return false;
  166.     }
  167.     // Build and store the theme
  168.     Builder builder( getIntf(), parser.getData() );
  169.     getIntf()->p_sys->p_theme = builder.build();
  170.     return true;
  171. }
  172. bool ThemeLoader::findThemeFile( const string &rootDir, string &themeFilePath )
  173. {
  174.     // Path separator
  175.     const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
  176.     DIR *pCurrDir;
  177.     struct dirent *pDirContent;
  178.     // Open the dir
  179.     pCurrDir = opendir( rootDir.c_str() );
  180.     if( pCurrDir == NULL )
  181.     {
  182.         // An error occurred
  183.         msg_Dbg( getIntf(), "Cannot open directory %s", rootDir.c_str() );
  184.         return false;
  185.     }
  186.     // Get the first directory entry
  187.     pDirContent = readdir( pCurrDir );
  188.     // While we still have entries in the directory
  189.     while( pDirContent != NULL )
  190.     {
  191.         string newURI = rootDir + sep + pDirContent->d_name;
  192.         // Skip . and ..
  193.         if( string( pDirContent->d_name ) != "." &&
  194.             string( pDirContent->d_name ) != ".." )
  195.         {
  196. #if defined( S_ISDIR )
  197.             struct stat stat_data;
  198.             stat( newURI.c_str(), &stat_data );
  199.             if( S_ISDIR(stat_data.st_mode) )
  200. #elif defined( DT_DIR )
  201.             if( pDirContent->d_type & DT_DIR )
  202. #else
  203.             if( 0 )
  204. #endif
  205.             {
  206.                 // Can we find the theme file in this subdirectory?
  207.                 if( findThemeFile( newURI, themeFilePath ) )
  208.                 {
  209.                     return true;
  210.                 }
  211.             }
  212.             else
  213.             {
  214.                 // Found the theme file?
  215.                 if( string( DEFAULT_XML_FILE ) ==
  216.                     string( pDirContent->d_name ) )
  217.                 {
  218.                     themeFilePath = newURI;
  219.                     return true;
  220.                 }
  221.             }
  222.         }
  223.         pDirContent = readdir( pCurrDir );
  224.     }
  225.     return false;
  226. }
  227. #if !defined( HAVE_LIBTAR_H ) && defined( HAVE_ZLIB_H )
  228. #ifdef WIN32
  229. #  define mkdir(dirname,mode) _mkdir(dirname)
  230. #endif
  231. /* Values used in typeflag field */
  232. #define REGTYPE  '0'            /* regular file */
  233. #define AREGTYPE ''           /* regular file */
  234. #define DIRTYPE  '5'            /* directory */
  235. #define BLOCKSIZE 512
  236. struct tar_header
  237. {                               /* byte offset */
  238.     char name[100];             /*   0 */
  239.     char mode[8];               /* 100 */
  240.     char uid[8];                /* 108 */
  241.     char gid[8];                /* 116 */
  242.     char size[12];              /* 124 */
  243.     char mtime[12];             /* 136 */
  244.     char chksum[8];             /* 148 */
  245.     char typeflag;              /* 156 */
  246.     char linkname[100];         /* 157 */
  247.     char magic[6];              /* 257 */
  248.     char version[2];            /* 263 */
  249.     char uname[32];             /* 265 */
  250.     char gname[32];             /* 297 */
  251.     char devmajor[8];           /* 329 */
  252.     char devminor[8];           /* 337 */
  253.     char prefix[155];           /* 345 */
  254.                                 /* 500 */
  255. };
  256. union tar_buffer {
  257.     char              buffer[BLOCKSIZE];
  258.     struct tar_header header;
  259. };
  260. /* helper functions */
  261. int getoct( char *p, int width );
  262. int makedir( char *newdir );
  263. int tar_open( TAR **t, char *pathname, int oflags )
  264. {
  265.     gzFile f = gzopen( pathname, "rb" );
  266.     if( f == NULL )
  267.     {
  268.         fprintf( stderr, "Couldn't gzopen %sn", pathname );
  269.         return -1;
  270.     }
  271.     *t = (gzFile *)malloc( sizeof(gzFile) );
  272.     **t = f;
  273.     return 0;
  274. }
  275. int tar_extract_all( TAR *t, char *prefix )
  276. {
  277.     union tar_buffer buffer;
  278.     int   len, err, getheader = 1, remaining = 0;
  279.     FILE  *outfile = NULL;
  280.     char  fname[BLOCKSIZE + PATH_MAX];
  281.     while( 1 )
  282.     {
  283.         len = gzread( *t, &buffer, BLOCKSIZE );
  284.         if( len < 0 )
  285.         {
  286.             fprintf( stderr, "%sn", gzerror(*t, &err) );
  287.         }
  288.         /*
  289.          * Always expect complete blocks to process
  290.          * the tar information.
  291.          */
  292.         if( len != 0 && len != BLOCKSIZE )
  293.         {
  294.             fprintf( stderr, "gzread: incomplete block readn" );
  295.             return -1;
  296.         }
  297.         /*
  298.          * If we have to get a tar header
  299.          */
  300.         if( getheader == 1 )
  301.         {
  302.             /*
  303.              * If we met the end of the tar
  304.              * or the end-of-tar block, we are done
  305.              */
  306.             if( (len == 0) || (buffer.header.name[0] == 0) )
  307.             {
  308.                 break;
  309.             }
  310.             sprintf( fname, "%s/%s", prefix, buffer.header.name );
  311.             /* Check magic value in header */
  312.             if( strncmp( buffer.header.magic, "GNUtar", 6 ) &&
  313.                 strncmp( buffer.header.magic, "ustar", 5 ) )
  314.             {
  315.                 //fprintf(stderr, "not a tar filen");
  316.                 return -1;
  317.             }
  318.             switch( buffer.header.typeflag )
  319.             {
  320.                 case DIRTYPE:
  321.                     makedir( fname );
  322.                     break;
  323.                 case REGTYPE:
  324.                 case AREGTYPE:
  325.                     remaining = getoct( buffer.header.size, 12 );
  326.                     if( remaining )
  327.                     {
  328.                         outfile = fopen( fname, "wb" );
  329.                         if( outfile == NULL )
  330.                         {
  331.                             /* try creating directory */
  332.                             char *p = strrchr( fname, '/' );
  333.                             if( p != NULL )
  334.                             {
  335.                                 *p = '';
  336.                                 makedir( fname );
  337.                                 *p = '/';
  338.                                 outfile = fopen( fname, "wb" );
  339.                                 if( !outfile )
  340.                                 {
  341.                                     fprintf( stderr, "tar couldn't create %sn",
  342.                                              fname );
  343.                                 }
  344.                             }
  345.                         }
  346.                     }
  347.                     else outfile = NULL;
  348.                 /*
  349.                  * could have no contents
  350.                  */
  351.                 getheader = (remaining) ? 0 : 1;
  352.                 break;
  353.             default:
  354.                 break;
  355.             }
  356.         }
  357.         else
  358.         {
  359.             unsigned int bytes = (remaining > BLOCKSIZE)?BLOCKSIZE:remaining;
  360.             if( outfile != NULL )
  361.             {
  362.                 if( fwrite( &buffer, sizeof(char), bytes, outfile ) != bytes )
  363.                 {
  364.                     fprintf( stderr, "error writing %s skipping...n", fname );
  365.                     fclose( outfile );
  366.                     unlink( fname );
  367.                 }
  368.             }
  369.             remaining -= bytes;
  370.             if( remaining == 0 )
  371.             {
  372.                 getheader = 1;
  373.                 if( outfile != NULL )
  374.                 {
  375.                     fclose(outfile);
  376.                     outfile = NULL;
  377.                 }
  378.             }
  379.         }
  380.     }
  381.     return 0;
  382. }
  383. int tar_close( TAR *t )
  384. {
  385.     if( gzclose( *t ) != Z_OK ) fprintf( stderr, "failed gzclosen" );
  386.     free( t );
  387.     return 0;
  388. }
  389. /* helper functions */
  390. int getoct( char *p, int width )
  391. {
  392.     int result = 0;
  393.     char c;
  394.     while( width-- )
  395.     {
  396.         c = *p++;
  397.         if( c == ' ' )
  398.             continue;
  399.         if( c == 0 )
  400.             break;
  401.         result = result * 8 + (c - '0');
  402.     }
  403.     return result;
  404. }
  405. /* Recursive make directory
  406.  * Abort if you get an ENOENT errno somewhere in the middle
  407.  * e.g. ignore error "mkdir on existing directory"
  408.  *
  409.  * return 1 if OK, 0 on error
  410.  */
  411. int makedir( char *newdir )
  412. {
  413.     char *p, *buffer = strdup( newdir );
  414.     int  len = strlen( buffer );
  415.     if( len <= 0 )
  416.     {
  417.         free( buffer );
  418.         return 0;
  419.     }
  420.     if( buffer[len-1] == '/' )
  421.     {
  422.         buffer[len-1] = '';
  423.     }
  424.     if( mkdir( buffer, 0775 ) == 0 )
  425.     {
  426.         free( buffer );
  427.         return 1;
  428.     }
  429.     p = buffer + 1;
  430.     while( 1 )
  431.     {
  432.         char hold;
  433.         while( *p && *p != '\' && *p != '/' ) p++;
  434.         hold = *p;
  435.         *p = 0;
  436.         if( ( mkdir( buffer, 0775 ) == -1 ) && ( errno == ENOENT ) )
  437.         {
  438.             fprintf( stderr, "couldn't create directory %sn", buffer );
  439.             free( buffer );
  440.             return 0;
  441.         }
  442.         if( hold == 0 ) break;
  443.         *p++ = hold;
  444.     }
  445.     free( buffer );
  446.     return 1;
  447. }
  448. #endif
  449. #ifdef HAVE_ZLIB_H
  450. int gzopen_frontend( char *pathname, int oflags, int mode )
  451. {
  452.     char *gzflags;
  453.     gzFile gzf;
  454.     switch( oflags & O_ACCMODE )
  455.     {
  456.         case O_WRONLY:
  457.             gzflags = "wb";
  458.             break;
  459.         case O_RDONLY:
  460.             gzflags = "rb";
  461.             break;
  462.         case O_RDWR:
  463.         default:
  464.             errno = EINVAL;
  465.             return -1;
  466.     }
  467.     gzf = gzopen( pathname, gzflags );
  468.     if( !gzf )
  469.     {
  470.         errno = ENOMEM;
  471.         return -1;
  472.     }
  473.     return (int)gzf;
  474. }
  475. #endif