theme_loader.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:20k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * theme_loader.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 the VideoLAN team
  5.  * $Id: d02fa718e1a777bb7c07b658631bd97ea93ba080 $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teulière <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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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/vlcproc.hpp"
  30. #include "../src/window_manager.hpp"
  31. #include <cctype>
  32. #ifdef HAVE_FCNTL_H
  33. #   include <fcntl.h>
  34. #endif
  35. #ifdef HAVE_SYS_STAT_H
  36. #   include <sys/stat.h>
  37. #endif
  38. #ifdef HAVE_UNISTD_H
  39. #   include <unistd.h>
  40. #elif defined( WIN32 ) && !defined( UNDER_CE )
  41. #   include <direct.h>
  42. #endif
  43. #ifdef HAVE_DIRENT_H
  44. #   include <dirent.h>
  45. #endif
  46. #if defined( HAVE_ZLIB_H )
  47. #   include <zlib.h>
  48. #   include <errno.h>
  49. int gzopen_frontend ( const char *pathname, int oflags, int mode );
  50. int gzclose_frontend( int );
  51. int gzread_frontend ( int, void *, size_t );
  52. int gzwrite_frontend( int, const void *, size_t );
  53. #if defined( HAVE_LIBTAR_H )
  54. #   include <libtar.h>
  55. #else
  56. typedef gzFile TAR;
  57. int tar_open        ( TAR **t, char *pathname, int oflags );
  58. int tar_extract_all ( TAR *t, char *prefix );
  59. int tar_close       ( TAR *t );
  60. int getoct( char *p, int width );
  61. #endif
  62. int makedir( const char *newdir );
  63. #endif
  64. #define DEFAULT_XML_FILE "theme.xml"
  65. #define WINAMP2_XML_FILE "winamp2.xml"
  66. #define ZIP_BUFFER_SIZE 4096
  67. bool ThemeLoader::load( const string &fileName )
  68. {
  69.     string path = getFilePath( fileName );
  70.     //Before all, let's see if the file is present
  71.     struct stat p_stat;
  72.     if( utf8_stat( path.c_str(), &p_stat ) )
  73.         return false;
  74.     // First, we try to un-targz the file, and if it fails we hope it's a XML
  75.     // file...
  76. #if defined( HAVE_ZLIB_H )
  77.     if( ! extract( sToLocale( fileName ) ) && ! parse( path, fileName ) )
  78.         return false;
  79. #else
  80.     if( ! parse( path, fileName ) )
  81.         return false;
  82. #endif
  83.     Theme *pNewTheme = getIntf()->p_sys->p_theme;
  84.     if( !pNewTheme )
  85.     {
  86.         return false;
  87.     }
  88.     // Check if the skin to load is in the config file, to load its config
  89.     char *skin_last = config_GetPsz( getIntf(), "skins2-last" );
  90.     if( skin_last != NULL && fileName == (string)skin_last )
  91.     {
  92.         // Restore the theme configuration
  93.         getIntf()->p_sys->p_theme->loadConfig();
  94.         // Used to anchor the windows at the beginning
  95.         pNewTheme->getWindowManager().stopMove();
  96.     }
  97.     else
  98.     {
  99.         config_PutPsz( getIntf(), "skins2-last", fileName.c_str() );
  100.         // Show the windows
  101.         pNewTheme->getWindowManager().showAll( true );
  102.     }
  103.     free( skin_last );
  104.     return true;
  105. }
  106. #if defined( HAVE_ZLIB_H )
  107. bool ThemeLoader::extractTarGz( const string &tarFile, const string &rootDir )
  108. {
  109.     TAR *t;
  110. #if defined( HAVE_LIBTAR_H )
  111.     tartype_t gztype = { (openfunc_t) gzopen_frontend,
  112.                          (closefunc_t) gzclose_frontend,
  113.                          (readfunc_t) gzread_frontend,
  114.                          (writefunc_t) gzwrite_frontend };
  115.     if( tar_open( &t, (char *)tarFile.c_str(), &gztype, O_RDONLY, 0,
  116.                   TAR_GNU ) == -1 )
  117. #else
  118.     if( tar_open( &t, (char *)tarFile.c_str(), O_RDONLY ) == -1 )
  119. #endif
  120.     {
  121.         return false;
  122.     }
  123.     if( tar_extract_all( t, (char *)rootDir.c_str() ) != 0 )
  124.     {
  125.         tar_close( t );
  126.         return false;
  127.     }
  128.     if( tar_close( t ) != 0 )
  129.     {
  130.         return false;
  131.     }
  132.     return true;
  133. }
  134. bool ThemeLoader::extractZip( const string &zipFile, const string &rootDir )
  135. {
  136.     // Try to open the ZIP file
  137.     unzFile file = unzOpen( zipFile.c_str() );
  138.     unz_global_info info;
  139.     if( unzGetGlobalInfo( file, &info ) != UNZ_OK )
  140.     {
  141.         return false;
  142.     }
  143.     // Extract all the files in the archive
  144.     for( unsigned long i = 0; i < info.number_entry; i++ )
  145.     {
  146.         if( !extractFileInZip( file, rootDir ) )
  147.         {
  148.             msg_Warn( getIntf(), "error while unzipping %s",
  149.                       zipFile.c_str() );
  150.             unzClose( file );
  151.             return false;
  152.         }
  153.         if( i < info.number_entry - 1 )
  154.         {
  155.             // Go the next file in the archive
  156.             if( unzGoToNextFile( file ) !=UNZ_OK )
  157.             {
  158.                 msg_Warn( getIntf(), "error while unzipping %s",
  159.                           zipFile.c_str() );
  160.                 unzClose( file );
  161.                 return false;
  162.             }
  163.         }
  164.     }
  165.     unzClose( file );
  166.     return true;
  167. }
  168. bool ThemeLoader::extractFileInZip( unzFile file, const string &rootDir )
  169. {
  170.     // Read info for the current file
  171.     char filenameInZip[256];
  172.     unz_file_info fileInfo;
  173.     if( unzGetCurrentFileInfo( file, &fileInfo, filenameInZip,
  174.                                sizeof( filenameInZip), NULL, 0, NULL, 0 )
  175.         != UNZ_OK )
  176.     {
  177.         return false;
  178.     }
  179. #ifdef WIN32
  180.     // Convert the file name to lower case, because some winamp skins
  181.     // use the wrong case...
  182.     for( size_t i=0; i< strlen( filenameInZip ); i++)
  183.     {
  184.         filenameInZip[i] = tolower( filenameInZip[i] );
  185.     }
  186. #endif
  187.     // Allocate the buffer
  188.     void *pBuffer = malloc( ZIP_BUFFER_SIZE );
  189.     if( !pBuffer )
  190.         return false;
  191.     // Get the path of the file
  192.     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
  193.     string fullPath = rootDir
  194.         + pOsFactory->getDirSeparator()
  195.         + fixDirSeparators( filenameInZip );
  196.     string basePath = getFilePath( fullPath );
  197.     // Extract the file if is not a directory
  198.     if( basePath != fullPath )
  199.     {
  200.         if( unzOpenCurrentFile( file ) )
  201.         {
  202.             free( pBuffer );
  203.             return false;
  204.         }
  205.         makedir( basePath.c_str() );
  206.         FILE *fout = fopen( fullPath.c_str(), "wb" );
  207.         if( fout == NULL )
  208.         {
  209.             msg_Err( getIntf(), "error opening %s", fullPath.c_str() );
  210.             free( pBuffer );
  211.             return false;
  212.         }
  213.         // Extract the current file
  214.         int n;
  215.         do
  216.         {
  217.             n = unzReadCurrentFile( file, pBuffer, ZIP_BUFFER_SIZE );
  218.             if( n < 0 )
  219.             {
  220.                 msg_Err( getIntf(), "error while reading zip file" );
  221.                 free( pBuffer );
  222.                 return false;
  223.             }
  224.             else if( n > 0 )
  225.             {
  226.                 if( fwrite( pBuffer, n , 1, fout) != 1 )
  227.                 {
  228.                     msg_Err( getIntf(), "error while writing %s",
  229.                              fullPath.c_str() );
  230.                     free( pBuffer );
  231.                     return false;
  232.                 }
  233.             }
  234.         } while( n > 0 );
  235.         fclose(fout);
  236.         if( unzCloseCurrentFile( file ) != UNZ_OK )
  237.         {
  238.             free( pBuffer );
  239.             return false;
  240.         }
  241.     }
  242.     free( pBuffer );
  243.     return true;
  244. }
  245. bool ThemeLoader::extract( const string &fileName )
  246. {
  247.     bool result = true;
  248.     char *tmpdir = tempnam( NULL, "vlt" );
  249.     string tempPath = sFromLocale( tmpdir );
  250.     free( tmpdir );
  251.     // Extract the file in a temporary directory
  252.     if( ! extractTarGz( fileName, tempPath ) &&
  253.         ! extractZip( fileName, tempPath ) )
  254.     {
  255.         deleteTempFiles( tempPath );
  256.         return false;
  257.     }
  258.     string path;
  259.     string xmlFile;
  260.     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
  261.     // Find the XML file in the theme
  262.     if( findFile( tempPath, DEFAULT_XML_FILE, xmlFile ) )
  263.     {
  264.         path = getFilePath( xmlFile );
  265.     }
  266.     else
  267.     {
  268.         // No XML file, check if it is a winamp2 skin
  269.         string mainBmp;
  270.         if( findFile( tempPath, "main.bmp", mainBmp ) )
  271.         {
  272.             msg_Dbg( getIntf(), "trying to load a winamp2 skin" );
  273.             path = getFilePath( mainBmp );
  274.             // Look for winamp2.xml in the resource path
  275.             list<string> resPath = pOsFactory->getResourcePath();
  276.             list<string>::const_iterator it;
  277.             for( it = resPath.begin(); it != resPath.end(); it++ )
  278.             {
  279.                 if( findFile( *it, WINAMP2_XML_FILE, xmlFile ) )
  280.                     break;
  281.             }
  282.         }
  283.     }
  284.     if( !xmlFile.empty() )
  285.     {
  286.         // Parse the XML file
  287.         if (! parse( path, xmlFile ) )
  288.         {
  289.             msg_Err( getIntf(), "error while parsing %s", xmlFile.c_str() );
  290.             result = false;
  291.         }
  292.     }
  293.     else
  294.     {
  295.         msg_Err( getIntf(), "no XML found in theme %s", fileName.c_str() );
  296.         result = false;
  297.     }
  298.     // Clean-up
  299.     deleteTempFiles( tempPath );
  300.     return result;
  301. }
  302. void ThemeLoader::deleteTempFiles( const string &path )
  303. {
  304.     OSFactory::instance( getIntf() )->rmDir( path );
  305. }
  306. #endif // HAVE_ZLIB_H
  307. bool ThemeLoader::parse( const string &path, const string &xmlFile )
  308. {
  309.     // File loaded
  310.     msg_Dbg( getIntf(), "using skin file: %s", xmlFile.c_str() );
  311.     // Start the parser
  312.     SkinParser parser( getIntf(), xmlFile, path );
  313.     if( ! parser.parse() )
  314.         return false;
  315.     // Build and store the theme
  316.     Builder builder( getIntf(), parser.getData(), path );
  317.     getIntf()->p_sys->p_theme = builder.build();
  318.     return true;
  319. }
  320. string ThemeLoader::getFilePath( const string &rFullPath )
  321. {
  322.     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
  323.     const string &sep = pOsFactory->getDirSeparator();
  324.     // Find the last separator ('/' or '')
  325.     string::size_type p = rFullPath.rfind( sep, rFullPath.size() );
  326.     string basePath;
  327.     if( p != string::npos )
  328.     {
  329.         if( p < rFullPath.size() - 1)
  330.         {
  331.             basePath = rFullPath.substr( 0, p );
  332.         }
  333.         else
  334.         {
  335.             basePath = rFullPath;
  336.         }
  337.     }
  338.     return basePath;
  339. }
  340. string ThemeLoader::fixDirSeparators( const string &rPath )
  341. {
  342.     OSFactory *pOsFactory = OSFactory::instance( getIntf() );
  343.     const string &sep = pOsFactory->getDirSeparator();
  344.     string::size_type p = rPath.find( "/", 0 );
  345.     string newPath = rPath;
  346.     while( p != string::npos )
  347.     {
  348.         newPath = newPath.replace( p, 1, sep );
  349.         p = newPath.find( "/", p + 1 );
  350.     }
  351.     return newPath;
  352. }
  353. bool ThemeLoader::findFile( const string &rootDir, const string &rFileName,
  354.                             string &themeFilePath )
  355. {
  356.     // Path separator
  357.     const string &sep = OSFactory::instance( getIntf() )->getDirSeparator();
  358.     DIR *pCurrDir;
  359.     char *pszDirContent;
  360.     // Open the dir
  361.     pCurrDir = utf8_opendir( rootDir.c_str() );
  362.     if( pCurrDir == NULL )
  363.     {
  364.         // An error occurred
  365.         msg_Dbg( getIntf(), "cannot open directory %s", rootDir.c_str() );
  366.         return false;
  367.     }
  368.     // While we still have entries in the directory
  369.     while( ( pszDirContent = utf8_readdir( pCurrDir ) ) != NULL )
  370.     {
  371.         string newURI = rootDir + sep + pszDirContent;
  372.         // Skip . and ..
  373.         if( string( pszDirContent ) != "." &&
  374.             string( pszDirContent ) != ".." )
  375.         {
  376. #if defined( S_ISDIR )
  377.             struct stat stat_data;
  378.             if( ( utf8_stat( newURI.c_str(), &stat_data ) == 0 )
  379.              && S_ISDIR(stat_data.st_mode) )
  380. #elif defined( DT_DIR )
  381.             if( pDirContent->d_type & DT_DIR )
  382. #else
  383.             if( 0 )
  384. #endif
  385.             {
  386.                 // Can we find the file in this subdirectory?
  387.                 if( findFile( newURI, rFileName, themeFilePath ) )
  388.                 {
  389.                     free( pszDirContent );
  390.                     closedir( pCurrDir );
  391.                     return true;
  392.                 }
  393.             }
  394.             else
  395.             {
  396.                 // Found the theme file?
  397.                 if( rFileName == string( pszDirContent ) )
  398.                 {
  399.                     themeFilePath = newURI;
  400.                     free( pszDirContent );
  401.                     closedir( pCurrDir );
  402.                     return true;
  403.                 }
  404.             }
  405.         }
  406.         free( pszDirContent );
  407.     }
  408.     closedir( pCurrDir );
  409.     return false;
  410. }
  411. #if !defined( HAVE_LIBTAR_H ) && defined( HAVE_ZLIB_H )
  412. /* Values used in typeflag field */
  413. #define REGTYPE  '0'            /* regular file */
  414. #define AREGTYPE ''           /* regular file */
  415. #define DIRTYPE  '5'            /* directory */
  416. #define BLOCKSIZE 512
  417. struct tar_header
  418. {                               /* byte offset */
  419.     char name[100];             /*   0 */
  420.     char mode[8];               /* 100 */
  421.     char uid[8];                /* 108 */
  422.     char gid[8];                /* 116 */
  423.     char size[12];              /* 124 */
  424.     char mtime[12];             /* 136 */
  425.     char chksum[8];             /* 148 */
  426.     char typeflag;              /* 156 */
  427.     char linkname[100];         /* 157 */
  428.     char magic[6];              /* 257 */
  429.     char version[2];            /* 263 */
  430.     char uname[32];             /* 265 */
  431.     char gname[32];             /* 297 */
  432.     char devmajor[8];           /* 329 */
  433.     char devminor[8];           /* 337 */
  434.     char prefix[155];           /* 345 */
  435.                                 /* 500 */
  436. };
  437. union tar_buffer {
  438.     char              buffer[BLOCKSIZE];
  439.     struct tar_header header;
  440. };
  441. int tar_open( TAR **t, char *pathname, int oflags )
  442. {
  443.     gzFile f = gzopen( pathname, "rb" );
  444.     if( f == NULL )
  445.     {
  446.         fprintf( stderr, "Couldn't gzopen %sn", pathname );
  447.         return -1;
  448.     }
  449.     *t = (gzFile *)malloc( sizeof(gzFile) );
  450.     **t = f;
  451.     return 0;
  452. }
  453. int tar_extract_all( TAR *t, char *prefix )
  454. {
  455.     union tar_buffer buffer;
  456.     int   len, err, getheader = 1, remaining = 0;
  457.     FILE  *outfile = NULL;
  458.     char  fname[BLOCKSIZE + PATH_MAX];
  459.     while( 1 )
  460.     {
  461.         len = gzread( *t, &buffer, BLOCKSIZE );
  462.         if( len < 0 )
  463.         {
  464.             fprintf( stderr, "%sn", gzerror(*t, &err) );
  465.         }
  466.         /*
  467.          * Always expect complete blocks to process
  468.          * the tar information.
  469.          */
  470.         if( len != 0 && len != BLOCKSIZE )
  471.         {
  472.             fprintf( stderr, "gzread: incomplete block readn" );
  473.             return -1;
  474.         }
  475.         /*
  476.          * If we have to get a tar header
  477.          */
  478.         if( getheader == 1 )
  479.         {
  480.             /*
  481.              * If we met the end of the tar
  482.              * or the end-of-tar block, we are done
  483.              */
  484.             if( (len == 0) || (buffer.header.name[0] == 0) )
  485.             {
  486.                 break;
  487.             }
  488.             sprintf( fname, "%s/%s", prefix, buffer.header.name );
  489.             /* Check magic value in header */
  490.             if( strncmp( buffer.header.magic, "GNUtar", 6 ) &&
  491.                 strncmp( buffer.header.magic, "ustar", 5 ) )
  492.             {
  493.                 //fprintf(stderr, "not a tar filen");
  494.                 return -1;
  495.             }
  496.             switch( buffer.header.typeflag )
  497.             {
  498.                 case DIRTYPE:
  499.                     makedir( fname );
  500.                     break;
  501.                 case REGTYPE:
  502.                 case AREGTYPE:
  503.                     remaining = getoct( buffer.header.size, 12 );
  504.                     if( remaining )
  505.                     {
  506.                         outfile = fopen( fname, "wb" );
  507.                         if( outfile == NULL )
  508.                         {
  509.                             /* try creating directory */
  510.                             char *p = strrchr( fname, '/' );
  511.                             if( p != NULL )
  512.                             {
  513.                                 *p = '';
  514.                                 makedir( fname );
  515.                                 *p = '/';
  516.                                 outfile = fopen( fname, "wb" );
  517.                                 if( !outfile )
  518.                                 {
  519.                                     fprintf( stderr, "tar couldn't create %sn",
  520.                                              fname );
  521.                                 }
  522.                             }
  523.                         }
  524.                     }
  525.                     else outfile = NULL;
  526.                 /*
  527.                  * could have no contents
  528.                  */
  529.                 getheader = (remaining) ? 0 : 1;
  530.                 break;
  531.             default:
  532.                 break;
  533.             }
  534.         }
  535.         else
  536.         {
  537.             unsigned int bytes = (remaining > BLOCKSIZE)?BLOCKSIZE:remaining;
  538.             if( outfile != NULL )
  539.             {
  540.                 if( fwrite( &buffer, sizeof(char), bytes, outfile ) != bytes )
  541.                 {
  542.                     fprintf( stderr, "error writing %s skipping...n", fname );
  543.                     fclose( outfile );
  544.                     outfile = NULL;
  545.                     unlink( fname );
  546.                 }
  547.             }
  548.             remaining -= bytes;
  549.             if( remaining == 0 )
  550.             {
  551.                 getheader = 1;
  552.                 if( outfile != NULL )
  553.                 {
  554.                     fclose(outfile);
  555.                     outfile = NULL;
  556.                 }
  557.             }
  558.         }
  559.     }
  560.     return 0;
  561. }
  562. int tar_close( TAR *t )
  563. {
  564.     if( gzclose( *t ) != Z_OK ) fprintf( stderr, "failed gzclosen" );
  565.     free( t );
  566.     return 0;
  567. }
  568. /* helper functions */
  569. int getoct( char *p, int width )
  570. {
  571.     int result = 0;
  572.     char c;
  573.     while( width-- )
  574.     {
  575.         c = *p++;
  576.         if( c == ' ' )
  577.             continue;
  578.         if( c == 0 )
  579.             break;
  580.         result = result * 8 + (c - '0');
  581.     }
  582.     return result;
  583. }
  584. #endif
  585. #ifdef WIN32
  586. #  define mkdir(dirname,mode) _mkdir(dirname)
  587. #endif
  588. /* Recursive make directory
  589.  * Abort if you get an ENOENT errno somewhere in the middle
  590.  * e.g. ignore error "mkdir on existing directory"
  591.  *
  592.  * return 1 if OK, 0 on error
  593.  */
  594. int makedir( const char *newdir )
  595. {
  596.     char *p, *buffer = strdup( newdir );
  597.     int  len = strlen( buffer );
  598.     if( len <= 0 )
  599.     {
  600.         free( buffer );
  601.         return 0;
  602.     }
  603.     if( buffer[len-1] == '/' )
  604.     {
  605.         buffer[len-1] = '';
  606.     }
  607.     if( mkdir( buffer, 0775 ) == 0 )
  608.     {
  609.         free( buffer );
  610.         return 1;
  611.     }
  612.     p = buffer + 1;
  613.     while( 1 )
  614.     {
  615.         char hold;
  616.         while( *p && *p != '\' && *p != '/' ) p++;
  617.         hold = *p;
  618.         *p = 0;
  619.         if( ( mkdir( buffer, 0775 ) == -1 ) && ( errno == ENOENT ) )
  620.         {
  621.             fprintf( stderr, "couldn't create directory %sn", buffer );
  622.             free( buffer );
  623.             return 0;
  624.         }
  625.         if( hold == 0 ) break;
  626.         *p++ = hold;
  627.     }
  628.     free( buffer );
  629.     return 1;
  630. }
  631. #ifdef HAVE_ZLIB_H
  632. static int currentGzFd = -1;
  633. static void * currentGzVp = NULL;
  634. int gzopen_frontend( const char *pathname, int oflags, int mode )
  635. {
  636.     const char *gzflags;
  637.     gzFile gzf;
  638.     switch( oflags )
  639.     {
  640.         case O_WRONLY:
  641.             gzflags = "wb";
  642.             break;
  643.         case O_RDONLY:
  644.             gzflags = "rb";
  645.             break;
  646.         case O_RDWR:
  647.         default:
  648.             errno = EINVAL;
  649.             return -1;
  650.     }
  651.     gzf = gzopen( pathname, gzflags );
  652.     if( !gzf )
  653.     {
  654.         errno = ENOMEM;
  655.         return -1;
  656.     }
  657.     /** Hum ... */
  658.     currentGzFd = 42;
  659.     currentGzVp = gzf;
  660.     return currentGzFd;
  661. }
  662. int gzclose_frontend( int fd )
  663. {
  664.     if( currentGzVp != NULL && fd != -1 )
  665.     {
  666.         void *toClose = currentGzVp;
  667.         currentGzVp = NULL;  currentGzFd = -1;
  668.         return gzclose( toClose );
  669.     }
  670.     return -1;
  671. }
  672. int gzread_frontend( int fd, void *p_buffer, size_t i_length )
  673. {
  674.     if( currentGzVp != NULL && fd != -1 )
  675.     {
  676.         return gzread( currentGzVp, p_buffer, i_length );
  677.     }
  678.     return -1;
  679. }
  680. int gzwrite_frontend( int fd, const void * p_buffer, size_t i_length )
  681. {
  682.     if( currentGzVp != NULL && fd != -1 )
  683.     {
  684.         return gzwrite( currentGzVp, const_cast<void*>(p_buffer), i_length );
  685.     }
  686.     return -1;
  687. }
  688. #endif