Commit 5fa7831e authored by Cyril Deguet's avatar Cyril Deguet

* all: support .zip for skin themes in addition to tar.gz (vlt)

  Borrowed code from Gilles Vollant for the unzip part
  (I guess this code should be put elsewhere in vlc, but it was
  the easy way for me at the moment;) I hope it compiles fine
  everywhere, I've tested only on linux.
  Now, everything's ready for winamp skins ;)
parent 17025142
......@@ -204,7 +204,7 @@ SOURCES_skins2 = \
x11/x11_window.hpp \
x11/x11_tooltip.cpp \
x11/x11_tooltip.hpp \
\
\
macosx/macosx_dragdrop.cpp \
macosx/macosx_dragdrop.hpp \
macosx/macosx_factory.cpp \
......@@ -218,5 +218,11 @@ SOURCES_skins2 = \
macosx/macosx_window.cpp \
macosx/macosx_window.hpp \
macosx/macosx_tooltip.cpp \
macosx/macosx_tooltip.hpp \
macosx/macosx_tooltip.hpp \
\
unzip/crypt.h \
unzip/ioapi.c \
unzip/ioapi.h \
unzip/unzip.c \
unzip/unzip.h \
$(NULL)
......@@ -61,10 +61,13 @@ typedef gzFile TAR;
int tar_open ( TAR **t, char *pathname, int oflags );
int tar_extract_all ( TAR *t, char *prefix );
int tar_close ( TAR *t );
int getoct( char *p, int width );
#endif
int makedir( const char *newdir );
#endif
#define DEFAULT_XML_FILE "theme.xml"
#define ZIP_BUFFER_SIZE 4096
bool ThemeLoader::load( const string &fileName )
......@@ -143,6 +146,131 @@ bool ThemeLoader::extractTarGz( const string &tarFile, const string &rootDir )
}
bool ThemeLoader::extractZip( const string &zipFile, const string &rootDir )
{
// Try to open the ZIP file
unzFile file = unzOpen( zipFile.c_str() );
unz_global_info info;
if( unzGetGlobalInfo( file, &info ) != UNZ_OK )
{
return false;
}
// Extract all the files in the archive
for( unsigned long i = 0; i < info.number_entry; i++ )
{
if( !extractFileInZip( file, rootDir ) )
{
msg_Warn( getIntf(), "Error while unzipping %s",
zipFile.c_str() );
return false;
}
if( i < info.number_entry - 1 )
{
// Go the next file in the archive
if( unzGoToNextFile( file ) !=UNZ_OK )
{
msg_Warn( getIntf(), "Error while unzipping %s",
zipFile.c_str() );
return false;
}
}
}
return true;
}
bool ThemeLoader::extractFileInZip( unzFile file, const string &rootDir )
{
// Read info for the current file
char filenameInZip[256];
unz_file_info fileInfo;
if( unzGetCurrentFileInfo( file, &fileInfo, filenameInZip,
sizeof( filenameInZip), NULL, 0, NULL, 0 )
!= UNZ_OK )
{
return false;
}
// Allocate the buffer
void *pBuffer = malloc( ZIP_BUFFER_SIZE );
if( !pBuffer )
{
msg_Err( getIntf(), "Failed to allocate memory" );
return false;
}
// Get the path of the file
string fullPath = rootDir + "/" + filenameInZip;
string::size_type pos = fullPath.rfind( '/' );
string basePath;
if( pos != string::npos )
{
if( pos < fullPath.size() - 1)
{
basePath = fullPath.substr( 0, pos );
}
else
{
basePath = fullPath;
}
}
// Extract the file if is not a directory
if( pos != fullPath.size() - 1 )
{
if( unzOpenCurrentFile( file ) )
{
free( pBuffer );
return false;
}
makedir( basePath.c_str() );
FILE *fout = fopen( fullPath.c_str(), "wb" );
if( fout == NULL )
{
msg_Err( getIntf(), "Error opening %s", fullPath.c_str() );
free( pBuffer );
return false;
}
// Extract the current file
int n;
do
{
n = unzReadCurrentFile( file, pBuffer, ZIP_BUFFER_SIZE );
if( n < 0 )
{
msg_Err( getIntf(), "Error while reading zip file" );
free( pBuffer );
return false;
}
else if( n > 0 )
{
if( fwrite( pBuffer, n , 1, fout) != 1 )
{
msg_Err( getIntf(), "Error while writing %s",
fullPath.c_str() );
free( pBuffer );
return false;
}
}
} while( n > 0 );
fclose(fout);
if( unzCloseCurrentFile( file ) != UNZ_OK )
{
free( pBuffer );
return false;
}
}
free( pBuffer );
return true;
}
bool ThemeLoader::extract( const string &fileName )
{
char *tmpdir = tempnam( NULL, "vlt" );
......@@ -150,7 +278,8 @@ bool ThemeLoader::extract( const string &fileName )
free( tmpdir );
// Extract the file in a temporary directory
if( ! extractTarGz( fileName, tempPath ) )
if( ! extractTarGz( fileName, tempPath ) &&
! extractZip( fileName, tempPath ) )
return false;
// Find the XML file and parse it
......@@ -280,10 +409,6 @@ bool ThemeLoader::findThemeFile( const string &rootDir, string &themeFilePath )
#if !defined( HAVE_LIBTAR_H ) && defined( HAVE_ZLIB_H )
#ifdef WIN32
# define mkdir(dirname,mode) _mkdir(dirname)
#endif
/* Values used in typeflag field */
#define REGTYPE '0' /* regular file */
#define AREGTYPE '\0' /* regular file */
......@@ -319,9 +444,6 @@ union tar_buffer {
};
/* helper functions */
int getoct( char *p, int width );
int makedir( char *newdir );
int tar_open( TAR **t, char *pathname, int oflags )
{
......@@ -483,6 +605,11 @@ int getoct( char *p, int width )
return result;
}
#endif
#ifdef WIN32
# define mkdir(dirname,mode) _mkdir(dirname)
#endif
/* Recursive make directory
* Abort if you get an ENOENT errno somewhere in the middle
......@@ -490,7 +617,7 @@ int getoct( char *p, int width )
*
* return 1 if OK, 0 on error
*/
int makedir( char *newdir )
int makedir( const char *newdir )
{
char *p, *buffer = strdup( newdir );
int len = strlen( buffer );
......@@ -532,7 +659,6 @@ int makedir( char *newdir )
free( buffer );
return 1;
}
#endif
#ifdef HAVE_ZLIB_H
......
......@@ -27,7 +27,9 @@
#include "skin_common.hpp"
#include <string>
#if defined( HAVE_ZLIB_H )
# include "../unzip/unzip.h"
#endif
class ThemeLoader: public SkinObject
{
......@@ -39,12 +41,18 @@ class ThemeLoader: public SkinObject
private:
#if defined( HAVE_ZLIB_H )
/// Extract files from an archive (currently only handles tar.gz)
/// Extract files from an archive (handles tar.gz and zip)
bool extract( const string &fileName );
/// Extract files from a tar.gz archive
bool extractTarGz( const string &tarFile, const string &rootDir );
/// Extract files from a .zip archive
bool extractZip( const string &zipFile, const string &rootDir );
/// Extract the current file from a .zip archive
bool extractFileInZip( unzFile file, const string &rootDir );
/// Clean up the temporary files created by the extraction
void deleteTempFiles( const string &path );
#endif
......
......@@ -120,7 +120,12 @@ void ThemeRepository::parseDirectory( const string &rDir )
while( pDirContent != NULL )
{
string name = pDirContent->d_name;
if( name.size() > 4 && name.substr( name.size() - 4, 4 ) == ".vlt" )
string extension;
if( name.size() > 4 )
{
extension = name.substr( name.size() - 4, 4 );
}
if( extension == ".vlt" || extension == ".zip" )
{
string path = rDir + sep + name;
msg_Dbg( getIntf(), "found skin %s", path.c_str() );
......
/* crypt.h -- base code for crypt/uncrypt ZIPfile
Version 1.01e, February 12th, 2005
Copyright (C) 1998-2005 Gilles Vollant
This code is a modified version of crypting code in Infozip distribution
The encryption/decryption parts of this source code (as opposed to the
non-echoing password parts) were originally written in Europe. The
whole source package can be freely distributed, including from the USA.
(Prior to January 2000, re-export from the US was a violation of US law.)
This encryption code is a direct transcription of the algorithm from
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
file (appnote.txt) is distributed with the PKZIP program (even in the
version without encryption capabilities).
If you don't need crypting in your application, just define symbols
NOCRYPT and NOUNCRYPT.
This code support the "Traditional PKWARE Encryption".
The new AES encryption added on Zip format by Winzip (see the page
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
Encryption is not supported.
*/
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
/***********************************************************************
* Return the next byte in the pseudo-random sequence
*/
static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
{
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
* unpredictable manner on 16-bit systems; not a problem
* with any known compiler so far, though */
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
}
/***********************************************************************
* Update the encryption keys with the next byte of plain text
*/
static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
{
(*(pkeys+0)) = CRC32((*(pkeys+0)), c);
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
{
register int keyshift = (int)((*(pkeys+1)) >> 24);
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
}
return c;
}
/***********************************************************************
* Initialize the encryption keys and the random header according to
* the given password.
*/
static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
{
*(pkeys+0) = 305419896L;
*(pkeys+1) = 591751049L;
*(pkeys+2) = 878082192L;
while (*passwd != '\0') {
update_keys(pkeys,pcrc_32_tab,(int)*passwd);
passwd++;
}
}
#define zdecode(pkeys,pcrc_32_tab,c) \
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
#define zencode(pkeys,pcrc_32_tab,c,t) \
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
#define RAND_HEAD_LEN 12
/* "last resort" source for second part of crypt seed pattern */
# ifndef ZCR_SEED2
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
# endif
static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
const char *passwd; /* password string */
unsigned char *buf; /* where to write header */
int bufSize;
unsigned long* pkeys;
const unsigned long* pcrc_32_tab;
unsigned long crcForCrypting;
{
int n; /* index in random header */
int t; /* temporary */
int c; /* random byte */
unsigned char header[RAND_HEAD_LEN-2]; /* random header */
static unsigned calls = 0; /* ensure different random header each time */
if (bufSize<RAND_HEAD_LEN)
return 0;
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
* output of rand() to get less predictability, since rand() is
* often poorly implemented.
*/
if (++calls == 1)
{
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
}
init_keys(passwd, pkeys, pcrc_32_tab);
for (n = 0; n < RAND_HEAD_LEN-2; n++)
{
c = (rand() >> 7) & 0xff;
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
}
/* Encrypt random header (last two bytes is high word of crc) */
init_keys(passwd, pkeys, pcrc_32_tab);
for (n = 0; n < RAND_HEAD_LEN-2; n++)
{
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
}
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
return n;
}
#endif
/* ioapi.c -- IO base function header for compress/uncompress .zip
files using zlib + zip or unzip API
Version 1.01e, February 12th, 2005
Copyright (C) 1998-2005 Gilles Vollant
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "zlib.h"
#include "ioapi.h"
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
voidpf ZCALLBACK fopen_file_func OF((
voidpf opaque,
const char* filename,
int mode));
uLong ZCALLBACK fread_file_func OF((
voidpf opaque,
voidpf stream,
void* buf,
uLong size));
uLong ZCALLBACK fwrite_file_func OF((
voidpf opaque,
voidpf stream,
const void* buf,
uLong size));
long ZCALLBACK ftell_file_func OF((
voidpf opaque,
voidpf stream));
long ZCALLBACK fseek_file_func OF((
voidpf opaque,
voidpf stream,
uLong offset,
int origin));
int ZCALLBACK fclose_file_func OF((
voidpf opaque,
voidpf stream));
int ZCALLBACK ferror_file_func OF((
voidpf opaque,
voidpf stream));
voidpf ZCALLBACK fopen_file_func (opaque, filename, mode)
voidpf opaque;
const char* filename;
int mode;
{
FILE* file = NULL;
const char* mode_fopen = NULL;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
mode_fopen = "rb";
else
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
mode_fopen = "r+b";
else
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
mode_fopen = "wb";
if ((filename!=NULL) && (mode_fopen != NULL))
file = fopen(filename, mode_fopen);
return file;
}
uLong ZCALLBACK fread_file_func (opaque, stream, buf, size)
voidpf opaque;
voidpf stream;
void* buf;
uLong size;
{
uLong ret;
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
return ret;
}
uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size)
voidpf opaque;
voidpf stream;
const void* buf;
uLong size;
{
uLong ret;
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
return ret;
}
long ZCALLBACK ftell_file_func (opaque, stream)
voidpf opaque;
voidpf stream;
{
long ret;
ret = ftell((FILE *)stream);
return ret;
}
long ZCALLBACK fseek_file_func (opaque, stream, offset, origin)
voidpf opaque;
voidpf stream;
uLong offset;
int origin;
{
int fseek_origin=0;
long ret;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
fseek_origin = SEEK_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END :
fseek_origin = SEEK_END;
break;
case ZLIB_FILEFUNC_SEEK_SET :
fseek_origin = SEEK_SET;
break;
default: return -1;
}
ret = 0;
fseek((FILE *)stream, offset, fseek_origin);
return ret;
}
int ZCALLBACK fclose_file_func (opaque, stream)
voidpf opaque;
voidpf stream;
{
int ret;
ret = fclose((FILE *)stream);
return ret;
}
int ZCALLBACK ferror_file_func (opaque, stream)
voidpf opaque;
voidpf stream;
{
int ret;
ret = ferror((FILE *)stream);
return ret;
}
void fill_fopen_filefunc (pzlib_filefunc_def)
zlib_filefunc_def* pzlib_filefunc_def;
{
pzlib_filefunc_def->zopen_file = fopen_file_func;
pzlib_filefunc_def->zread_file = fread_file_func;
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
pzlib_filefunc_def->ztell_file = ftell_file_func;
pzlib_filefunc_def->zseek_file = fseek_file_func;
pzlib_filefunc_def->zclose_file = fclose_file_func;
pzlib_filefunc_def->zerror_file = ferror_file_func;
pzlib_filefunc_def->opaque = NULL;
}
/* ioapi.h -- IO base function header for compress/uncompress .zip
files using zlib + zip or unzip API
Version 1.01e, February 12th, 2005
Copyright (C) 1998-2005 Gilles Vollant
*/
#ifndef _ZLIBIOAPI_H
#define _ZLIBIOAPI_H
#define ZLIB_FILEFUNC_SEEK_CUR (1)
#define ZLIB_FILEFUNC_SEEK_END (2)
#define ZLIB_FILEFUNC_SEEK_SET (0)
#define ZLIB_FILEFUNC_MODE_READ (1)
#define ZLIB_FILEFUNC_MODE_WRITE (2)
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
#define ZLIB_FILEFUNC_MODE_CREATE (8)
#ifndef ZCALLBACK
#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
#define ZCALLBACK CALLBACK
#else
#define ZCALLBACK
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
typedef struct zlib_filefunc_def_s
{
open_file_func zopen_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell_file_func ztell_file;
seek_file_func zseek_file;
close_file_func zclose_file;
testerror_file_func zerror_file;
voidpf opaque;
} zlib_filefunc_def;
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
#ifdef __cplusplus
}
#endif
#endif
This diff is collapsed.
/* unzip.h -- IO for uncompress .zip files using zlib
Version 1.01e, February 12th, 2005
Copyright (C) 1998-2005 Gilles Vollant
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
WinZip, InfoZip tools and compatible.
Multi volume ZipFile (span) are not supported.
Encryption compatible with pkzip 2.04g only supported
Old compressions used by old PKZip 1.x are not supported
I WAIT FEEDBACK at mail info@winimage.com
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
Condition of use and distribution are the same than zlib :
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* for more info about .ZIP format, see
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
http://www.info-zip.org/pub/infozip/doc/
PkWare has also a specification at :
ftp://ftp.pkware.com/probdesc.zip
*/
#ifndef _unz_H
#define _unz_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _ZLIB_H
#include "zlib.h"
#endif
#ifndef _ZLIBIOAPI_H
#include "ioapi.h"
#endif
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagunzFile__ { int unused; } unzFile__;
typedef unzFile__ *unzFile;