2006-10-28 19:45:02 +00:00
/*
* util . cpp
*
* This file is a part of NSIS .
*
2013-05-17 19:31:36 +00:00
* Copyright ( C ) 1999 - 2013 Nullsoft and Contributors
2006-10-28 19:45:02 +00:00
*
* Licensed under the zlib / libpng license ( the " License " ) ;
* you may not use this file except in compliance with the License .
*
* Licence details can be found in the file COPYING .
*
* This software is provided ' as - is ' , without any express or implied
* warranty .
*/
2010-03-29 14:24:47 +00:00
2010-03-24 17:22:56 +00:00
/* Unicode support by Jim Park -- 07/23/2007 */
2010-03-29 14:24:47 +00:00
2004-01-30 22:04:10 +00:00
# include "Platform.h"
2002-08-02 10:01:35 +00:00
# include <stdio.h>
# include <stdarg.h>
2004-08-18 16:14:44 +00:00
# include <time.h>
2004-08-20 15:40:38 +00:00
# include <string.h>
2010-03-24 17:22:56 +00:00
# include "tchar.h"
2002-08-02 10:01:35 +00:00
# include "exehead/fileform.h"
# include "util.h"
# include "strlist.h"
2007-04-13 09:54:54 +00:00
# include "winchar.h"
2013-05-04 13:32:47 +00:00
# include "utf.h"
2010-03-29 14:24:47 +00:00
2004-08-20 15:40:38 +00:00
# ifndef _WIN32
# include <ctype.h>
2004-10-11 21:24:54 +00:00
# include <unistd.h> // for close(2)
# include <fcntl.h> // for open(2)
2004-12-11 16:06:17 +00:00
# include <iconv.h>
2009-01-17 22:32:19 +00:00
# include <locale.h>
2004-08-20 15:40:38 +00:00
# endif
2006-04-28 15:54:42 +00:00
# ifdef __APPLE__
namespace Apple { // defines struct section
# include <mach-o / dyld.h> // for _NSGetExecutablePath
} ;
2009-01-15 13:51:22 +00:00
# define FALSE 0 // bugs #1851365, #2497290
# define TRUE 1
2006-04-28 15:54:42 +00:00
# include <sys / param.h> // for MAXPATHLEN
# endif
2004-10-02 15:17:00 +00:00
# include <cassert> // for assert
2005-08-30 16:30:48 +00:00
# include <algorithm>
2006-02-04 15:01:18 +00:00
# include <stdexcept>
2013-07-25 22:00:53 +00:00
# include <errno.h>
2004-10-02 15:17:00 +00:00
2005-08-27 19:56:00 +00:00
using namespace std ;
2004-09-30 20:25:33 +00:00
2002-08-02 10:01:35 +00:00
extern int g_display_errors ;
extern FILE * g_output ;
2010-05-04 22:28:53 +00:00
double my_wtof ( const wchar_t * str )
{
2013-03-07 21:25:35 +00:00
char buf [ 100 ] ;
WideCharToMultiByte ( 0 , 0 , str , - 1 , buf , 100 , 0 , 0 ) ;
return atof ( buf ) ;
2010-05-04 22:28:53 +00:00
}
2013-03-07 21:25:35 +00:00
unsigned int my_strncpy ( TCHAR * Dest , const TCHAR * Src , unsigned int cchMax )
{
// Dest and Src must be valid, Dest is always \0 terminated.
// Returns number of TCHARs copied to Dest; min(strlen(Src),cchMax-1).
unsigned int cch = 0 ;
if ( cchMax )
{
for ( ; - - cchMax ; )
{
TCHAR ch = Src [ cch ] ;
if ( ! ch ) break ;
Dest [ cch + + ] = ch ;
}
Dest [ cch ] = _T ( ' \0 ' ) ;
}
return cch ;
}
2010-05-04 22:28:53 +00:00
2002-08-02 10:01:35 +00:00
// Returns 0 if everything is OK
2003-05-09 19:50:16 +00:00
// Returns -1 if can't find the file
// Returns -2 if the file is an invalid bitmap
// Returns -3 if the size doesn't match
// Returns -4 if the bpp doesn't match
2010-03-24 17:22:56 +00:00
int update_bitmap ( CResourceEditor * re , WORD id , const TCHAR * filename , int width /*=0*/ , int height /*=0*/ , int maxbpp /*=0*/ ) {
2012-03-01 21:06:14 +00:00
FILE * f = FOPEN ( filename , ( " rb " ) ) ;
2002-08-02 10:01:35 +00:00
if ( ! f ) return - 1 ;
if ( fgetc ( f ) ! = ' B ' | | fgetc ( f ) ! = ' M ' ) {
fclose ( f ) ;
2003-05-09 19:50:16 +00:00
return - 2 ;
2002-08-02 10:01:35 +00:00
}
if ( width ! = 0 ) {
2010-03-27 19:20:16 +00:00
INT32 biWidth ;
2002-08-02 10:01:35 +00:00
fseek ( f , 18 , SEEK_SET ) ; // Seek to the width member of the header
2010-03-27 19:20:16 +00:00
fread ( & biWidth , sizeof ( INT32 ) , 1 , f ) ;
2006-03-11 18:14:59 +00:00
FIX_ENDIAN_INT32_INPLACE ( biWidth ) ;
2002-08-02 10:01:35 +00:00
if ( width ! = biWidth ) {
fclose ( f ) ;
2003-05-09 19:50:16 +00:00
return - 3 ;
2002-08-02 10:01:35 +00:00
}
}
if ( height ! = 0 ) {
2010-03-27 19:20:16 +00:00
INT32 biHeight ;
2002-08-02 10:01:35 +00:00
fseek ( f , 22 , SEEK_SET ) ; // Seek to the height member of the header
2010-03-27 19:20:16 +00:00
fread ( & biHeight , sizeof ( INT32 ) , 1 , f ) ;
2006-03-11 18:14:59 +00:00
FIX_ENDIAN_INT32_INPLACE ( biHeight ) ;
2003-05-09 19:50:16 +00:00
// Bitmap height can be negative too...
2002-08-02 10:01:35 +00:00
if ( height ! = abs ( biHeight ) ) {
fclose ( f ) ;
2003-05-09 19:50:16 +00:00
return - 3 ;
}
}
if ( maxbpp ! = 0 ) {
WORD biBitCount ;
fseek ( f , 28 , SEEK_SET ) ; // Seek to the height member of the header
fread ( & biBitCount , sizeof ( WORD ) , 1 , f ) ;
2006-03-11 18:14:59 +00:00
FIX_ENDIAN_INT16_INPLACE ( biBitCount ) ;
2003-05-09 19:50:16 +00:00
if ( biBitCount > maxbpp ) {
fclose ( f ) ;
return - 4 ;
2002-08-02 10:01:35 +00:00
}
}
DWORD dwSize ;
fseek ( f , 2 , SEEK_SET ) ;
fread ( & dwSize , sizeof ( DWORD ) , 1 , f ) ;
2006-03-11 18:14:59 +00:00
FIX_ENDIAN_INT32_INPLACE ( dwSize ) ;
2002-08-02 10:01:35 +00:00
dwSize - = 14 ;
unsigned char * bitmap = ( unsigned char * ) malloc ( dwSize ) ;
2013-03-19 02:11:37 +00:00
if ( ! bitmap ) {
2002-08-02 10:01:35 +00:00
fclose ( f ) ;
2013-03-19 02:11:37 +00:00
throw bad_alloc ( ) ;
2002-08-02 10:01:35 +00:00
}
2013-03-19 02:11:37 +00:00
bool gotbmdata = ! fseek ( f , 14 , SEEK_SET ) & & dwSize = = fread ( bitmap , 1 , dwSize , f ) ;
int retval = gotbmdata ? 0 : - 2 ;
2002-08-02 10:01:35 +00:00
fclose ( f ) ;
2013-03-19 02:11:37 +00:00
if ( gotbmdata )
re - > UpdateResource ( RT_BITMAP , id , NSIS_DEFAULT_LANG , bitmap , dwSize ) ;
2002-08-02 10:01:35 +00:00
2003-09-12 11:16:33 +00:00
free ( bitmap ) ;
2013-03-19 02:11:37 +00:00
return retval ;
2002-08-02 10:01:35 +00:00
}
2004-03-29 20:21:00 +00:00
# ifndef _WIN32
2010-03-24 17:22:56 +00:00
TCHAR * CharPrev ( const TCHAR * s , const TCHAR * p ) {
2004-03-29 20:21:00 +00:00
if ( ! s | | ! p | | p < s )
return NULL ;
while ( * s ) {
2010-03-24 17:22:56 +00:00
TCHAR * n = CharNext ( s ) ;
2004-03-29 20:21:00 +00:00
if ( n > = p )
break ;
s = n ;
2002-08-06 11:24:49 +00:00
}
2010-03-24 17:22:56 +00:00
return ( TCHAR * ) s ;
2004-03-29 20:21:00 +00:00
}
2012-03-01 21:06:14 +00:00
char * CharNextA ( const char * s ) {
2004-03-29 20:21:00 +00:00
int l = 0 ;
if ( s & & * s )
2004-08-20 15:40:38 +00:00
l = max ( 1 , mblen ( s , MB_CUR_MAX ) ) ;
2012-03-01 21:06:14 +00:00
return ( char * ) s + l ;
}
WCHAR * CharNextW ( const WCHAR * s ) {
// BUGBUG: Is this the best we can do?
return s + 1 ;
2004-03-29 20:21:00 +00:00
}
2007-07-18 19:18:00 +00:00
char * CharNextExA ( WORD codepage , const char * s , int flags ) {
2012-10-13 01:47:50 +00:00
char buf [ 30 ] ;
snprintf ( buf , 30 , " CP%d " , codepage ) ;
2012-03-01 21:06:14 +00:00
const char * orglocct = setlocale ( LC_CTYPE , buf ) ;
2007-07-18 19:18:00 +00:00
const char * np ;
int len = mblen ( s , strlen ( s ) ) ;
if ( len > 0 )
np = s + len ;
else
np = s + 1 ;
2012-03-01 21:06:14 +00:00
setlocale ( LC_CTYPE , orglocct ) ;
2007-07-18 19:18:00 +00:00
return ( char * ) np ;
}
2010-03-24 17:22:56 +00:00
int wsprintf ( TCHAR * s , const TCHAR * format , . . . ) {
2004-03-29 20:21:00 +00:00
va_list val ;
va_start ( val , format ) ;
2010-03-24 17:22:56 +00:00
int res = _vsntprintf ( s , 1024 , format , val ) ;
2004-03-29 20:21:00 +00:00
va_end ( val ) ;
return res ;
2002-08-06 11:24:49 +00:00
}
2004-05-08 13:05:35 +00:00
2013-04-03 22:46:17 +00:00
bool nsis_iconv_reallociconv ( iconv_t CD , char * * In , size_t * cbInLeft , char * * Mem , size_t & cbConverted )
{
char * in , * heap = * Mem ;
UINT cbMem = 512 ;
size_t inleft , outleft , icvret = ( size_t ) - 1 ;
for ( ; ; )
{
in = * In , inleft = * cbInLeft , outleft = cbMem - sizeof ( UINT32 ) ; // Leave room for \0
char * p = ( char * ) realloc ( heap , cbMem ) , * out = p ;
if ( ! p ) break ;
heap = p , icvret = nsis_iconv_adaptor ( iconv , CD , & in , & inleft , & out , & outleft ) ;
if ( ( size_t ) - 1 ! = icvret | | E2BIG ! = errno ) break ;
cbMem * = 4 ;
}
* In = in , * Mem = heap ;
cbConverted = cbMem - ( outleft + sizeof ( UINT32 ) ) , * cbInLeft = inleft ;
if ( ( size_t ) - 1 ! = icvret )
{
* ( ( UINT32 * ) ( & heap [ cbConverted ] ) ) = 0 ;
return true ;
}
return false ;
}
2010-03-24 17:22:56 +00:00
void static create_code_page_string ( TCHAR * buf , size_t len , UINT code_page ) {
2011-12-05 23:44:26 +00:00
switch ( code_page )
{
case CP_ACP :
2013-03-07 21:25:35 +00:00
case 1 : // OEMCP
2004-12-11 16:06:17 +00:00
code_page = 1252 ;
2011-12-05 23:44:26 +00:00
break ;
case CP_UTF8 :
_sntprintf ( buf , len , _T ( " UTF-8 " ) ) ;
return ;
2013-04-03 22:46:17 +00:00
case 1200 : // UTF16LE
case 1201 : // UTF16BE
_sntprintf ( buf , len , _T ( " UTF-16%cE " ) , 1200 = = code_page ? _T ( ' L ' ) : _T ( ' B ' ) ) ;
return ;
2011-12-05 23:44:26 +00:00
}
2010-03-24 17:22:56 +00:00
_sntprintf ( buf , len , _T ( " CP%d " ) , code_page ) ;
2004-12-11 16:06:17 +00:00
}
int WideCharToMultiByte ( UINT CodePage , DWORD dwFlags , LPCWSTR lpWideCharStr ,
int cchWideChar , LPSTR lpMultiByteStr , int cbMultiByte , LPCSTR lpDefaultChar ,
LPBOOL lpUsedDefaultChar ) {
2011-12-05 23:44:26 +00:00
static char buffer [ 4096 ] ; // BUGBUG: Should this be 4*NSIS_MAX_STRLEN for large string build?
2004-12-11 16:06:17 +00:00
char cp [ 128 ] ;
create_code_page_string ( cp , sizeof ( cp ) , CodePage ) ;
2013-03-07 21:25:35 +00:00
iconv_t cd = iconv_open ( cp , " wchar_t " ) ;
2004-12-11 16:06:17 +00:00
if ( cd = = ( iconv_t ) - 1 ) {
return 0 ;
}
if ( cchWideChar < 0 ) {
2010-04-30 14:48:19 +00:00
cchWideChar = ( int ) _wcslen ( lpWideCharStr ) + 1 ;
2004-12-11 16:06:17 +00:00
}
if ( cbMultiByte = = 0 ) {
cbMultiByte = sizeof ( buffer ) ;
lpMultiByteStr = buffer ;
}
char * in = ( char * ) lpWideCharStr ;
char * out = lpMultiByteStr ;
size_t inbytes = cchWideChar * sizeof ( WCHAR ) ;
size_t outbytes = cbMultiByte ;
2009-01-17 22:32:19 +00:00
if ( nsis_iconv_adaptor ( iconv , cd , & in , & inbytes , & out , & outbytes ) = = ( size_t ) - 1 ) {
2004-12-11 16:06:17 +00:00
iconv_close ( cd ) ;
return 0 ;
}
iconv_close ( cd ) ;
return cbMultiByte - outbytes ;
}
int MultiByteToWideChar ( UINT CodePage , DWORD dwFlags , LPCSTR lpMultiByteStr ,
int cbMultiByte , LPWSTR lpWideCharStr , int cchWideChar ) {
2011-12-05 23:44:26 +00:00
static WCHAR buffer [ 4096 ] ; // BUGBUG: Should this be 4*NSIS_MAX_STRLEN for large string build?
2004-12-11 16:06:17 +00:00
char cp [ 128 ] ;
create_code_page_string ( cp , sizeof ( cp ) , CodePage ) ;
2013-03-07 21:25:35 +00:00
iconv_t cd = iconv_open ( " wchar_t " , cp ) ;
2004-12-11 16:06:17 +00:00
if ( cd = = ( iconv_t ) - 1 ) {
return 0 ;
}
if ( cbMultiByte < 0 ) {
cbMultiByte = strlen ( lpMultiByteStr ) + 1 ;
}
if ( cchWideChar = = 0 ) {
cchWideChar = sizeof ( buffer ) ;
lpWideCharStr = buffer ;
}
char * in = ( char * ) lpMultiByteStr ;
char * out = ( char * ) lpWideCharStr ;
size_t inbytes = cbMultiByte ;
size_t outbytes = cchWideChar * sizeof ( WCHAR ) ;
2009-01-17 22:32:19 +00:00
if ( nsis_iconv_adaptor ( iconv , cd , & in , & inbytes , & out , & outbytes ) = = ( size_t ) - 1 ) {
2004-12-11 16:06:17 +00:00
iconv_close ( cd ) ;
return 0 ;
}
iconv_close ( cd ) ;
return cchWideChar - ( outbytes / sizeof ( WCHAR ) ) ;
}
2007-07-18 19:26:16 +00:00
BOOL IsValidCodePage ( UINT CodePage )
{
2010-03-24 17:22:56 +00:00
TCHAR cp [ 128 ] ;
2007-07-18 19:26:16 +00:00
create_code_page_string ( cp , sizeof ( cp ) , CodePage ) ;
2013-03-07 21:25:35 +00:00
iconv_t cd = iconv_open ( _T ( " wchar_t " ) , cp ) ;
2007-07-18 19:26:16 +00:00
if ( cd = = ( iconv_t ) - 1 )
return FALSE ;
iconv_close ( cd ) ;
return TRUE ;
}
2012-03-01 21:06:14 +00:00
# ifdef _UNICODE
void PathConvertWinToPosix ( char * p )
2004-08-20 15:40:38 +00:00
{
2012-03-01 21:06:14 +00:00
if ( ' \" ' = = * p ) + + p ; // Skip opening quote if any (For !system)
size_t len = strlen ( p ) ;
2004-08-20 15:40:38 +00:00
2012-03-01 21:06:14 +00:00
/* Replace drive letter X: by /X */
if ( len > = 2 & & ' : ' = = p [ 1 ] )
2004-08-20 15:40:38 +00:00
{
2012-03-01 21:06:14 +00:00
p [ 1 ] = ( char ) tolower ( ( int ) p [ 0 ] ) ;
p [ 0 ] = ' / ' ;
2004-08-20 15:40:38 +00:00
}
2012-03-01 21:06:14 +00:00
do
2004-08-20 15:40:38 +00:00
{
2012-03-01 21:06:14 +00:00
if ( ' \\ ' = = * p ) * p = ' / ' ;
p = CharNextA ( p ) ;
2004-08-20 15:40:38 +00:00
}
2012-03-01 21:06:14 +00:00
while ( * p ) ;
}
# endif
void PathConvertWinToPosix ( TCHAR * p )
{
if ( _T ( ' \" ' ) = = * p ) + + p ; // Skip opening quote if any (For !system)
size_t len = _tcsclen ( p ) ;
2004-08-20 15:40:38 +00:00
2012-03-01 21:06:14 +00:00
/* Replace drive letter X: by /X */
if ( len > = 2 & & _T ( ' : ' ) = = p [ 1 ] )
{
p [ 1 ] = ( TCHAR ) tolower ( ( int ) p [ 0 ] ) ;
p [ 0 ] = _T ( ' / ' ) ;
}
2004-08-20 15:40:38 +00:00
do
{
2012-03-01 21:06:14 +00:00
if ( _T ( ' \\ ' ) = = * p ) * p = _T ( ' / ' ) ;
2004-08-20 15:40:38 +00:00
p = CharNext ( p ) ;
}
while ( * p ) ;
2012-03-01 21:06:14 +00:00
}
# define MY_ERROR_MSG(x) {if (g_display_errors) {PrintColorFmtMsg_ERR(_T("%s"), x);}}
2004-05-08 13:05:35 +00:00
2012-03-01 21:06:14 +00:00
TCHAR * my_convert ( const TCHAR * path )
{
TCHAR * converted_path = _tcsdup ( path ) ;
if ( ! converted_path )
{
MY_ERROR_MSG ( _T ( " Error: could not allocate memory in my_convert() \n " ) ) ;
return 0 ;
}
PathConvertWinToPosix ( converted_path ) ;
2004-08-20 15:40:38 +00:00
return converted_path ;
}
2010-03-24 17:22:56 +00:00
void my_convert_free ( TCHAR * converted_path )
2004-08-20 15:40:38 +00:00
{
free ( converted_path ) ;
}
2010-03-24 17:22:56 +00:00
int my_open ( const TCHAR * pathname , int flags )
2004-08-20 15:40:38 +00:00
{
2010-03-24 17:22:56 +00:00
TCHAR * converted_pathname = my_convert ( pathname ) ;
2009-03-28 09:56:49 +00:00
int result = open ( converted_pathname , flags ) ;
my_convert_free ( converted_pathname ) ;
2004-08-20 15:40:38 +00:00
return result ;
}
2012-03-01 21:06:14 +00:00
# endif //!_WIN32
2004-08-20 15:40:38 +00:00
2012-03-01 21:06:14 +00:00
FILE * my_fopen ( const TCHAR * path , const char * mode )
2004-08-20 15:40:38 +00:00
{
2012-03-01 21:06:14 +00:00
FILE * f = 0 ;
# ifndef _UNICODE
f = fopen ( path , mode ) ;
# else
# ifdef _WIN32
TCHAR tmode [ 20 ] ;
for ( int i = 0 ; ; + + i ) if ( 0 = = ( tmode [ i ] = mode [ i ] ) ) break ;
f = _wfopen ( path , tmode ) ;
# else
const char * orglocct = setlocale ( LC_CTYPE , " " ) ;
const wchar_t * srcW = path ;
size_t cb = wcsrtombs ( 0 , & srcW , 0 , 0 ) ;
if ( - 1 ! = cb )
{
char * nativepath = ( char * ) malloc ( + + cb ) ;
if ( nativepath )
{
cb = wcsrtombs ( nativepath , & path , cb , 0 ) ;
if ( - 1 ! = cb )
{
PathConvertWinToPosix ( nativepath ) ;
f = fopen ( nativepath , mode ) ;
}
free ( nativepath ) ;
}
}
setlocale ( LC_CTYPE , orglocct ) ;
# endif
# endif
return f ;
2004-08-20 15:40:38 +00:00
}
2012-03-01 21:06:14 +00:00
2002-11-27 16:04:34 +00:00
2013-07-27 18:29:36 +00:00
void * operator new ( size_t size ) NSIS_CXX_THROWSPEC ( bad_alloc ) {
2003-05-09 19:50:16 +00:00
void * p = malloc ( size ) ;
if ( ! p )
throw bad_alloc ( ) ;
return p ;
2002-11-27 16:04:34 +00:00
}
2007-07-23 18:43:07 +00:00
void operator delete ( void * p ) throw ( ) {
2003-05-09 19:50:16 +00:00
if ( p ) free ( p ) ;
2002-11-27 16:04:34 +00:00
}
2007-07-23 18:43:07 +00:00
void operator delete [ ] ( void * p ) throw ( ) {
2003-05-09 19:50:16 +00:00
if ( p ) free ( p ) ;
2004-03-12 20:43:54 +00:00
}
2004-08-18 16:14:44 +00:00
2010-03-24 17:22:56 +00:00
size_t my_strftime ( TCHAR * s , size_t max , const TCHAR * fmt , const struct tm * tm ) {
return _tcsftime ( s , max , fmt , tm ) ;
2004-08-18 16:14:44 +00:00
}
2004-09-30 20:25:33 +00:00
2010-03-24 17:22:56 +00:00
tstring get_full_path ( const tstring & path ) {
2004-09-30 20:25:33 +00:00
# ifdef _WIN32
2010-03-24 17:22:56 +00:00
TCHAR * throwaway ;
TCHAR real_path [ 1024 ] ;
2004-09-30 20:25:33 +00:00
int rc = GetFullPathName ( path . c_str ( ) , 1024 , real_path , & throwaway ) ;
assert ( rc < = 1024 ) ; // path size is limited by MAX_PATH (260)
assert ( rc ! = 0 ) ; // rc==0 in case of error
2010-03-24 17:22:56 +00:00
return tstring ( real_path ) ;
2004-10-01 19:52:56 +00:00
# else //_WIN32
# ifdef PATH_MAX
2010-03-24 17:22:56 +00:00
static TCHAR buffer [ PATH_MAX ] ;
2004-10-01 19:52:56 +00:00
# else //PATH_MAX
2008-03-03 14:04:53 +00:00
int path_max = pathconf ( path . c_str ( ) , _PC_PATH_MAX ) ;
2004-10-01 19:52:56 +00:00
if ( path_max < = 0 )
path_max = 4096 ;
2010-03-24 17:22:56 +00:00
TCHAR * buffer = ( TCHAR * ) malloc ( path_max * sizeof ( TCHAR ) ) ;
2004-10-01 19:52:56 +00:00
if ( ! buffer )
2010-03-24 17:22:56 +00:00
return tstring ( path ) ;
2004-10-01 19:52:56 +00:00
# endif //PATH_MAX
if ( ! realpath ( path . c_str ( ) , buffer ) )
2010-03-24 17:22:56 +00:00
_tcscpy ( buffer , path . c_str ( ) ) ;
tstring result ( buffer ) ;
2004-10-01 19:52:56 +00:00
# ifndef PATH_MAX
free ( buffer ) ;
# endif //!PATH_MAX
2004-09-30 20:25:33 +00:00
return result ;
# endif //_WIN32
}
2004-10-01 19:52:56 +00:00
2010-03-24 17:22:56 +00:00
tstring get_string_prefix ( const tstring & str , const tstring & separator ) {
const tstring : : size_type last_separator_pos = str . rfind ( separator ) ;
2004-10-01 19:52:56 +00:00
if ( last_separator_pos = = string : : npos )
2005-08-27 19:56:00 +00:00
return str ;
return str . substr ( 0 , last_separator_pos ) ;
2004-10-01 19:52:56 +00:00
}
2004-10-11 21:24:54 +00:00
2010-03-24 17:22:56 +00:00
tstring get_string_suffix ( const tstring & str , const tstring & separator ) {
const tstring : : size_type last_separator_pos = str . rfind ( separator ) ;
if ( last_separator_pos = = tstring : : npos )
2005-08-27 19:56:00 +00:00
return str ;
2010-03-24 17:22:56 +00:00
return str . substr ( last_separator_pos + separator . size ( ) , tstring : : npos ) ;
2005-08-27 19:56:00 +00:00
}
2010-03-24 17:22:56 +00:00
tstring get_dir_name ( const tstring & path ) {
2005-08-27 19:56:00 +00:00
return get_string_prefix ( path , PLATFORM_PATH_SEPARATOR_STR ) ;
}
2010-03-24 17:22:56 +00:00
tstring get_file_name ( const tstring & path ) {
2005-08-27 19:56:00 +00:00
return get_string_suffix ( path , PLATFORM_PATH_SEPARATOR_STR ) ;
2004-11-26 15:26:49 +00:00
}
2004-11-30 18:00:27 +00:00
2010-03-24 17:22:56 +00:00
tstring get_executable_path ( const TCHAR * argv0 ) {
2004-11-30 18:00:27 +00:00
# ifdef _WIN32
2010-03-24 17:22:56 +00:00
TCHAR temp_buf [ MAX_PATH + 1 ] ;
temp_buf [ 0 ] = _T ( ' \0 ' ) ;
2006-03-15 06:51:31 +00:00
int rc = GetModuleFileName ( NULL , temp_buf , MAX_PATH ) ;
2004-11-30 18:00:27 +00:00
assert ( rc ! = 0 ) ;
2010-03-24 17:22:56 +00:00
return tstring ( temp_buf ) ;
2006-03-15 06:51:31 +00:00
# elif __APPLE__
2010-03-24 17:22:56 +00:00
TCHAR temp_buf [ MAXPATHLEN + 1 ] ;
2006-04-28 15:54:42 +00:00
unsigned int buf_len = MAXPATHLEN ;
int rc = Apple : : _NSGetExecutablePath ( temp_buf , & buf_len ) ;
2006-03-15 06:51:31 +00:00
assert ( rc = = 0 ) ;
2010-03-24 17:22:56 +00:00
return tstring ( temp_buf ) ;
2006-03-15 06:51:31 +00:00
# else /* Linux/BSD/POSIX/etc */
2010-03-24 17:22:56 +00:00
const TCHAR * envpath = _tgetenv ( _T ( " _ " ) ) ;
2006-03-24 18:15:53 +00:00
if ( envpath ! = NULL ) return get_full_path ( envpath ) ;
2006-03-15 06:51:31 +00:00
else {
2010-03-24 17:22:56 +00:00
TCHAR * pathtmp ;
TCHAR * path = NULL ;
2006-03-15 06:51:31 +00:00
size_t len = 100 ;
2007-07-23 18:43:07 +00:00
int nchars ;
2006-03-15 06:51:31 +00:00
while ( 1 ) {
2010-03-24 17:22:56 +00:00
pathtmp = ( TCHAR * ) realloc ( path , len + 1 ) ;
2006-03-15 06:51:31 +00:00
if ( pathtmp = = NULL ) {
free ( path ) ;
return get_full_path ( argv0 ) ;
}
path = pathtmp ;
2010-03-24 17:22:56 +00:00
nchars = readlink ( _T ( " /proc/self/exe " ) , path , len ) ;
2007-07-23 18:43:07 +00:00
if ( nchars = = - 1 ) {
2006-03-15 06:51:31 +00:00
free ( path ) ;
return get_full_path ( argv0 ) ;
}
2007-07-23 18:43:07 +00:00
if ( nchars < ( int ) len ) {
2010-03-24 17:22:56 +00:00
path [ nchars ] = _T ( ' \0 ' ) ;
2006-03-15 06:51:31 +00:00
string result ( path ) ;
free ( path ) ;
return result ;
}
len * = 2 ;
}
}
2004-11-30 18:00:27 +00:00
# endif
}
2010-03-24 17:22:56 +00:00
tstring get_executable_dir ( const TCHAR * argv0 ) {
2004-11-30 18:00:27 +00:00
return get_dir_name ( get_executable_path ( argv0 ) ) ;
}
2005-08-27 19:56:00 +00:00
2010-03-24 17:22:56 +00:00
tstring remove_file_extension ( const tstring & path ) {
return get_string_prefix ( path , _T ( " . " ) ) ;
2005-08-27 19:56:00 +00:00
}
2008-03-03 14:04:53 +00:00
struct ToLower
{
2010-03-24 17:22:56 +00:00
TCHAR operator ( ) ( TCHAR c ) const { return _totlower ( c ) ; }
2008-03-03 14:04:53 +00:00
} ;
2010-03-24 17:22:56 +00:00
tstring lowercase ( const tstring & str ) {
tstring result = str ;
2008-03-03 14:04:53 +00:00
transform ( str . begin ( ) , str . end ( ) , result . begin ( ) , ToLower ( ) ) ;
2005-08-27 19:56:00 +00:00
return result ;
}
2006-07-30 10:29:23 +00:00
2013-03-10 22:26:27 +00:00
/*
* ExpandoStrFmtVaList returns the number of characters written excluding
* the \ 0 terminator or 0 on error .
* realloc ( ) is used on * ppMalloc if cchStack is not
* large enough to hold the formated string .
*/
size_t ExpandoStrFmtVaList ( wchar_t * Stack , size_t cchStack , wchar_t * * ppMalloc , const wchar_t * FmtStr , va_list Args )
{
# ifdef _WIN32
2013-07-25 22:00:53 +00:00
// For _vsnwprintf, the \0 terminator is not part of the input size
# if _MSC_VER <= 1310
# define ExpandoStrFmtVaList_vsnwprintf(d,c,f,v) _vsnwprintf((d),(c)?(c)-1:0,(f),(v)) // Allow INT_MAX hack on MinGW and older versions of VC that don't have _vscwprintf
# else
# define ExpandoStrFmtVaList_vsnwprintf(d,c,f,v) ( INT_MAX==(c) ? _vscwprintf((f),(v)) : _vsnwprintf((d),(c)?(c)-1:0,(f),(v)) )
# endif
2013-03-10 22:26:27 +00:00
# else
2013-07-25 22:00:53 +00:00
# define ExpandoStrFmtVaList_vsnwprintf vswprintf
2013-03-10 22:26:27 +00:00
# endif
# if defined(_ISOC99_SOURCE) || _POSIX_C_SOURCE >= 200112L
const bool cansizecalc = true , msvcbackdoor = false ;
# else
static char testedsizecalc = 0 ;
if ( ! testedsizecalc )
{
# ifdef _WIN32
size_t cch = ExpandoStrFmtVaList_vsnwprintf ( 0 , INT_MAX , L " 333 " , Args ) ;
# else
wchar_t testbuf [ 1 + 1 ] ;
size_t cch = ExpandoStrFmtVaList_vsnwprintf ( testbuf , COUNTOF ( testbuf ) , L " 333 " , Args ) ;
# endif
testedsizecalc = ( 3 = = cch ) + 1 ;
}
# ifdef _WIN32
const bool msvcbackdoor = ! ! ( testedsizecalc - 1 ) , cansizecalc = false ;
# else
const bool cansizecalc = ! ! ( testedsizecalc - 1 ) , msvcbackdoor = false ;
# endif
# endif
size_t & cchAvail = cchStack , cch ;
wchar_t * & dest = Stack , * mem = * ppMalloc ;
for ( ; ; )
{
cch = ExpandoStrFmtVaList_vsnwprintf ( dest , cchAvail , FmtStr , Args ) ;
2013-03-10 23:02:09 +00:00
if ( ( unsigned ) - 1 = = cch )
2013-03-10 22:26:27 +00:00
{
cch = 0 ;
if ( cansizecalc ) break ; // vswprintf error, abort!
if ( msvcbackdoor )
cchAvail = ExpandoStrFmtVaList_vsnwprintf ( 0 , INT_MAX , FmtStr , Args ) + 1 ;
else
cchAvail = 4 * STD_MAX ( cchAvail , ( size_t ) 500 ) ;
}
else
{
if ( cch < cchAvail ) break ; // We are done.
cchAvail = + + cch ; // cch from vswprintf did not include the \0 terminator
}
dest = mem = ( wchar_t * ) realloc ( mem , cchAvail * sizeof ( wchar_t ) ) ;
if ( ! mem ) return 0 ;
}
* ppMalloc = mem ;
return cch ;
}
2013-05-04 13:32:47 +00:00
# if defined(_WIN32) && defined(_UNICODE)
int RunChildProcessRedirected ( LPCWSTR cmdprefix , LPCWSTR cmdmain )
{
// We have to deliver the requested output encoding to our host (if any) and the
// only way to do that is to convert the pipe content from what we hope is UTF-8.
// The reason we need a pipe in the first place is because we cannot trust the
// child to call GetConsoleOutputCP(), and even if we could, UTF-16 is not valid there.
UINT cp = CP_UTF8 , mbtwcf = MB_ERR_INVALID_CHARS ;
errno = ENOMEM ;
if ( ! cmdprefix ) cmdprefix = _T ( " " ) ;
UINT cch1 = _tcslen ( cmdprefix ) , cch2 = _tcslen ( cmdmain ) ;
WCHAR * cmd = ( WCHAR * ) malloc ( ( cch1 + cch2 + 1 ) * sizeof ( WCHAR ) ) ;
if ( ! cmd ) return - 1 ;
_tcscpy ( cmd , cmdprefix ) ;
_tcscat ( cmd , cmdmain ) ;
SECURITY_DESCRIPTOR sd = { 1 , 0 , SE_DACL_PRESENT , NULL , } ;
SECURITY_ATTRIBUTES sa = { sizeof ( sa ) , & sd , true } ;
const UINT orgwinconcp = GetConsoleCP ( ) , orgwinconoutcp = GetConsoleOutputCP ( ) ;
HANDLE hPipRd , hPipWr ;
PROCESS_INFORMATION pi ;
BOOL ok = CreatePipe ( & hPipRd , & hPipWr , & sa , 0 ) ;
if ( ! ok )
hPipRd = 0 , hPipWr = 0 ;
else
{
STARTUPINFO si = { sizeof ( si ) } ;
si . dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW ;
si . wShowWindow = SW_HIDE ;
si . hStdOutput = si . hStdError = hPipWr ;
si . hStdInput = INVALID_HANDLE_VALUE ;
errno = ECHILD ;
SetConsoleOutputCP ( cp ) ;
ok = CreateProcess ( 0 , cmd , 0 , 0 , TRUE , 0 , 0 , 0 , & si , & pi ) ;
CloseHandle ( hPipWr ) ; // We want ERROR_BROKEN_PIPE when the child is done
}
free ( cmd ) ;
DWORD childec = - 1 ;
if ( ok )
{
bool utf8 = true , okt ;
char iobuf [ 512 ] ;
DWORD cbRead , cbOfs = 0 , cchwb = 0 ;
WCHAR wbuf [ 100 ] , wchbuf [ 2 + 1 ] ; // A surrogate pair + \0
for ( ; ; )
{
BOOL okr = ReadFile ( hPipRd , iobuf + cbOfs , sizeof ( iobuf ) - cbOfs , & cbRead , 0 ) ;
cbRead + = cbOfs , cbOfs = 0 ;
unsigned char cbTrail , cch ;
for ( DWORD i = 0 ; i < cbRead ; )
{
cch = 0 ;
if ( utf8 )
{
okt = UTF8_GetTrailCount ( iobuf [ i ] , cbTrail ) ;
if ( ! okt ) // Not UTF-8? Switching to ACP
{
switchtoacp : cp = CP_ACP , mbtwcf = 0 , utf8 = false ;
SetConsoleOutputCP ( cp ) ;
continue ;
}
if ( ! cbTrail ) cch + + , wchbuf [ 0 ] = iobuf [ i ] ; // ASCII
}
else
{
cbTrail = ! ! IsDBCSLeadByteEx ( cp , iobuf [ i ] ) ;
}
if ( i + cbTrail > = cbRead ) // Read more first?
{
memmove ( iobuf , iobuf + i , cbOfs = cbRead - i ) ;
if ( okr ) break ; else i = 0 ;
}
if ( ! cch )
{
cch = MultiByteToWideChar ( cp , mbtwcf , & iobuf [ i ] , 1 + cbTrail , wchbuf , COUNTOF ( wchbuf ) - 1 ) ;
if ( ! cch )
{
if ( utf8 ) goto switchtoacp ;
cch + + , wchbuf [ 0 ] = UNICODE_REPLACEMENT_CHARACTER ;
}
}
i + = 1 + cbTrail ;
if ( 0xfeff = = wchbuf [ 0 ] & & 1 = = cch ) cch = 0 ; // MakeNsisW is not a fan of the BOM, eat it.
if ( ! cch ) continue ;
wbuf [ cchwb + + ] = wchbuf [ 0 ] ;
if ( - - cch ) wbuf [ cchwb + + ] = wchbuf [ 1 ] ;
const bool fullbuf = cchwb + cch > = COUNTOF ( wbuf ) - 1 ; // cch is 1 for surrogate pairs
if ( ! okr | | fullbuf | | L ' \n ' = = wchbuf [ 0 ] ) // Stop on \n so \r\n conversion has enough context (...\r\n vs ...\n)
{
# ifdef MAKENSIS
extern WINSIO_OSDATA g_osdata_stdout ;
WinStdIO_OStreamWrite ( g_osdata_stdout , wbuf , cchwb ) ; // Faster than _ftprintf
# else
wbuf [ cchwb ] = L ' \0 ' ;
_ftprintf ( g_output , _T ( " %s " ) , wbuf ) ;
# endif
cchwb = 0 ;
}
}
if ( ! okr ) break ;
}
WaitForSingleObject ( pi . hProcess , INFINITE ) ;
GetExitCodeProcess ( pi . hProcess , & childec ) ;
CloseHandle ( pi . hThread ) ;
CloseHandle ( pi . hProcess ) ;
}
SetConsoleCP ( orgwinconcp ) ; SetConsoleOutputCP ( orgwinconoutcp ) ;
CloseHandle ( hPipRd ) ;
return childec ;
}
# endif
2013-03-10 22:26:27 +00:00
2013-05-04 13:32:47 +00:00
int sane_system ( const TCHAR * command )
{
2006-07-30 10:29:23 +00:00
# ifdef _WIN32
// workaround for bug #1509909
// http://sf.net/tracker/?func=detail&atid=373085&aid=1509909&group_id=22049
//
// cmd.exe /C has some weird handling for quotes. it strips
// the surrounding quotes, if they exist. if there are quotes
// around the program path and its arguments, it will strip
// the outer quotes. this may result in something like:
// `program files\nsis\makensis.exe" "args`
// which obviously fails...
//
2013-05-04 13:32:47 +00:00
// to avoid the stripping, a harmless string is prefixed to the command line.
const TCHAR * prefix = _T ( " IF 1==1 " ) ;
# ifdef _UNICODE
if ( ! command ) return 0 ;
if ( ! * command ) return 1 ;
tstring fixedcmd = _tgetenv ( _T ( " COMSPEC " ) ) ;
if ( ! fixedcmd . length ( ) ) fixedcmd = _T ( " CMD.EXE " ) ;
fixedcmd + = _T ( " /C " ) ;
fixedcmd + = prefix ;
return RunChildProcessRedirected ( fixedcmd . c_str ( ) , command ) ;
# else
tstring fixedcmd = prefix + _T ( " " ) + command ;
return _tsystem ( fixedcmd . c_str ( ) ) ;
# endif
2006-07-30 10:29:23 +00:00
# else
2010-03-24 17:22:56 +00:00
return _tsystem ( command ) ;
2006-07-30 10:29:23 +00:00
# endif
}
2007-04-24 14:06:50 +00:00
2013-05-04 13:32:47 +00:00
# ifdef _WIN32
bool GetFileSize64 ( HANDLE hFile , ULARGE_INTEGER & uli )
{
uli . LowPart = GetFileSize ( hFile , & uli . HighPart ) ;
return INVALID_FILE_SIZE ! = uli . LowPart | | ! GetLastError ( ) ;
}
# endif
# if defined(_WIN32) && defined(_UNICODE) && defined(MAKENSIS)
# include <io.h> // for _get_osfhandle
bool WINAPI WinStdIO_OStreamInit ( WINSIO_OSDATA & osd , FILE * strm , WORD cp , int bom )
{
// bom < 0: override cp if UTF detected but never write BOM
// bom = 0: ignore BOM and force cp
// bom > 0: override cp if UTF detected, write BOM if it does not already exist
const int fd = _fileno ( strm ) ;
osd . mode = 0 , osd . hCRT = strm , osd . hNative = ( HANDLE ) _get_osfhandle ( fd ) ;
if ( INVALID_HANDLE_VALUE = = osd . hNative ) return false ;
DWORD conmode ;
if ( GetConsoleMode ( osd . hNative , & conmode ) ) osd . mode + + ; else osd . mode - - ;
bool succ = NStream : : SetBinaryMode ( fd ) ;
DWORD cbio = 0 ;
ULARGE_INTEGER uli ;
2013-05-04 14:33:09 +00:00
if ( succ & & 0 ! = bom & & GetFileSize64 ( osd . hNative , uli ) & & uli . QuadPart )
2013-05-04 13:32:47 +00:00
{
OVERLAPPED olap = { 0 } ; // Used to read from start of file
unsigned char bufbom [ 4 ] ;
if ( ReadFile ( osd . hNative , bufbom , sizeof ( bufbom ) , & cbio , & olap ) )
{
UINT detbom = DetectUTFBOM ( bufbom , cbio ) ;
if ( detbom ) cp = ( WORD ) detbom , bom = 0 ;
}
SetFilePointer ( osd . hNative , 0 , 0 , FILE_END ) ;
}
osd . mustwritebom = bom > 0 & & ! cbio , osd . cp = cp ;
return succ | | ( sizeof ( TCHAR ) - 1 & & WinStdIO_IsConsole ( osd ) ) ; // Don't care about BOM for WriteConsoleW
}
bool WINAPI WinStdIO_OStreamWrite ( WINSIO_OSDATA & osd , const wchar_t * Str , UINT cch )
{
if ( ( unsigned ) - 1 = = cch ) cch = _tcslen ( Str ) ;
DWORD cbio ;
if ( WinStdIO_IsConsole ( osd ) )
return ! ! WriteConsoleW ( osd . hNative , Str , cch , & cbio , 0 ) | | ! cch ;
NOStream strm ( osd . hCRT ) ;
NStreamEncoding & enc = strm . StreamEncoding ( ) ;
enc . SetCodepage ( osd . cp ) ;
bool retval = false ;
if ( osd . mustwritebom )
{
osd . mustwritebom = false ;
if ( enc . IsUnicode ( ) & & ! strm . WriteBOM ( enc ) )
{
osd . mode = 1 , osd . hNative = 0 ; // Something is wrong, stop writing!
goto end ;
}
}
retval = strm . WritePlatformNLString ( Str , cch ) ;
end :
strm . Detach ( ) ;
return retval ;
}
int WINAPI WinStdIO_vfwprintf ( FILE * strm , const wchar_t * Fmt , va_list val )
{
if ( g_output = = strm & & Fmt )
{
extern WINSIO_OSDATA g_osdata_stdout ;
ExpandoString < wchar_t , NSIS_MAX_STRLEN > buf ;
errno = ENOMEM ;
UINT cch = buf . StrFmt ( Fmt , val , false ) ;
if ( cch & & ! WinStdIO_OStreamWrite ( g_osdata_stdout , buf , cch ) )
{
cch = 0 , errno = EIO ;
}
return cch ? cch : ( * Fmt ? - 1 : 0 ) ;
}
return vfwprintf ( strm , Fmt , val ) ;
}
int WinStdIO_fwprintf ( FILE * strm , const wchar_t * Fmt , . . . )
{
va_list val ;
va_start ( val , Fmt ) ;
int rv = _vftprintf ( strm , Fmt , val ) ;
va_end ( val ) ;
return rv ;
}
int WinStdIO_wprintf ( const wchar_t * Fmt , . . . )
{
va_list val ;
va_start ( val , Fmt ) ;
int rv = _vftprintf ( g_output , Fmt , val ) ;
va_end ( val ) ;
return rv ;
}
# endif
2010-03-24 17:22:56 +00:00
2011-11-09 10:30:11 +00:00
void PrintColorFmtMsg ( unsigned int type , const TCHAR * fmtstr , va_list args )
{
# ifdef _WIN32
const HANDLE hWin32Con = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
static INT32 contxtattrbak = - 1 ;
WORD txtattr = 0 ;
if ( contxtattrbak < 0 )
{
if ( - 1 = = contxtattrbak )
{
CONSOLE_SCREEN_BUFFER_INFO csbi ;
contxtattrbak = - 2 ;
if ( GetConsoleScreenBufferInfo ( hWin32Con , & csbi ) )
{
contxtattrbak = csbi . wAttributes ;
goto gottxtattrbak ;
}
}
}
else
{
gottxtattrbak :
switch ( type & 0xF )
{
case 0 : goto resettxtattr ;
case 1 : txtattr = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED ; break ;
case 2 : txtattr = FOREGROUND_INTENSITY | FOREGROUND_RED ; break ;
}
2013-05-04 13:32:47 +00:00
// Use original background color if our text will still be readable
if ( ( contxtattrbak & 0xF0 ) ! = ( txtattr < < 4 ) ) txtattr | = ( contxtattrbak & 0xF0 ) ;
if ( ( txtattr & 0xFF ) = = 0xFE ) txtattr & = ~ FOREGROUND_INTENSITY ; // BrightYellow on BrightWhite is hard to read
2011-11-09 10:30:11 +00:00
SetConsoleTextAttribute ( hWin32Con , txtattr ) ;
}
# endif
if ( fmtstr ) _vftprintf ( g_output , fmtstr , args ) ;
fflush ( g_output ) ;
# ifdef _WIN32
if ( contxtattrbak > = 0 & & ! ( 0x10 & type ) )
{
resettxtattr :
SetConsoleTextAttribute ( hWin32Con , contxtattrbak ) ;
}
# endif
}
void FlushOutputAndResetPrintColor ( )
{
fflush ( g_output ) ;
# ifdef _WIN32
PrintColorFmtMsg ( 0 , NULL , ( va_list ) NULL ) ; //va_list is just a pointer on windows so this is ok
# endif
}
2010-03-24 17:22:56 +00:00
static bool GetDLLVersionUsingRE ( const tstring & filepath , DWORD & high , DWORD & low )
2007-04-24 14:06:50 +00:00
{
bool found = false ;
2012-03-01 21:06:14 +00:00
FILE * fdll = FOPEN ( filepath . c_str ( ) , ( " rb " ) ) ;
2007-04-24 14:06:50 +00:00
if ( ! fdll )
return 0 ;
fseek ( fdll , 0 , SEEK_END ) ;
unsigned int len = ftell ( fdll ) ;
fseek ( fdll , 0 , SEEK_SET ) ;
LPBYTE dll = ( LPBYTE ) malloc ( len ) ;
if ( ! dll )
{
fclose ( fdll ) ;
return 0 ;
}
if ( fread ( dll , 1 , len , fdll ) ! = len )
{
fclose ( fdll ) ;
free ( dll ) ;
return 0 ;
}
2013-03-19 02:11:37 +00:00
fclose ( fdll ) ;
2007-04-24 14:06:50 +00:00
try
{
CResourceEditor * dllre = new CResourceEditor ( dll , len ) ;
2010-04-12 16:00:17 +00:00
LPBYTE ver = dllre - > GetResource ( VS_FILE_INFO , VS_VERSION_INFO , 0 ) ;
int versize = dllre - > GetResourceSize ( VS_FILE_INFO , VS_VERSION_INFO , 0 ) ;
2007-04-24 14:06:50 +00:00
if ( ver )
{
if ( ( size_t ) versize > sizeof ( WORD ) * 3 )
{
// get VS_FIXEDFILEINFO from VS_VERSIONINFO
WCHAR * szKey = ( WCHAR * ) ( ver + sizeof ( WORD ) * 3 ) ;
2010-04-30 14:48:19 +00:00
int len = ( wcslen ( szKey ) + 1 ) * sizeof ( WCHAR ) + sizeof ( WORD ) * 3 ;
2007-04-24 14:06:50 +00:00
len = ( len + 3 ) & ~ 3 ; // align on DWORD boundry
VS_FIXEDFILEINFO * verinfo = ( VS_FIXEDFILEINFO * ) ( ver + len ) ;
if ( versize > len & & verinfo - > dwSignature = = VS_FFI_SIGNATURE )
{
low = verinfo - > dwFileVersionLS ;
high = verinfo - > dwFileVersionMS ;
found = true ;
}
}
dllre - > FreeResource ( ver ) ;
}
delete dllre ;
}
catch ( exception & )
{
}
return found ;
}
2010-03-24 17:22:56 +00:00
static bool GetDLLVersionUsingAPI ( const tstring & filepath , DWORD & high , DWORD & low )
2007-04-24 14:06:50 +00:00
{
bool found = false ;
# ifdef _WIN32
2010-03-24 17:22:56 +00:00
TCHAR path [ 1024 ] ;
TCHAR * name ;
2007-04-24 14:06:50 +00:00
path [ 0 ] = 0 ;
GetFullPathName ( filepath . c_str ( ) , 1024 , path , & name ) ;
DWORD d ;
DWORD verSize = GetFileVersionInfoSize ( path , & d ) ;
if ( verSize )
{
void * buf = ( void * ) GlobalAlloc ( GPTR , verSize ) ;
if ( buf )
{
UINT uLen ;
VS_FIXEDFILEINFO * pvsf ;
2010-03-24 17:22:56 +00:00
if ( GetFileVersionInfo ( path , 0 , verSize , buf ) & & VerQueryValue ( buf , _T ( " \\ " ) , ( void * * ) & pvsf , & uLen ) )
2007-04-24 14:06:50 +00:00
{
low = pvsf - > dwFileVersionLS ;
high = pvsf - > dwFileVersionMS ;
found = true ;
}
GlobalFree ( buf ) ;
}
}
# endif
return found ;
}
2007-04-24 14:24:18 +00:00
# ifdef _WIN32
// the following structure must be byte-aligned.
# pragma pack( push, pre_vxd_ver, 1 )
typedef struct _VXD_VERSION_RESOURCE {
2010-03-24 17:22:56 +00:00
char cType ; // Should not be converted to TCHAR (JP)
2007-04-24 14:24:18 +00:00
WORD wID ;
2010-03-24 17:22:56 +00:00
char cName ; // Should not be converted to TCHAR (JP)
2007-04-24 14:24:18 +00:00
WORD wOrdinal ;
WORD wFlags ;
DWORD dwResSize ;
BYTE bVerData ;
} VXD_VERSION_RESOURCE , * PVXD_VERSION_RESOURCE ;
# pragma pack( pop, pre_vxd_ver )
2010-03-24 17:22:56 +00:00
static BOOL GetVxdVersion ( LPCTSTR szFile , LPDWORD lpdwLen , LPVOID lpData )
2007-04-24 14:24:18 +00:00
{
HANDLE hFile = NULL ;
HANDLE hFileMapping = NULL ;
void * pView = NULL ;
DWORD dwSize = 0 ;
DWORD dwError = 0 ;
PIMAGE_DOS_HEADER pDosExeHdr = NULL ;
PIMAGE_NT_HEADERS pNtExeHdr = NULL ;
PIMAGE_VXD_HEADER pLEHdr = NULL ;
PVXD_VERSION_RESOURCE pVerRes = NULL ;
LPVOID pRawRes = NULL ;
// Open the file for shared read access.
hFile = CreateFile ( szFile , GENERIC_READ , FILE_SHARE_READ ,
NULL , OPEN_EXISTING , 0 , NULL ) ;
if ( hFile = = INVALID_HANDLE_VALUE )
{
return FALSE ;
}
// Create a read-only file mapping object for the file.
hFileMapping = CreateFileMapping ( hFile , NULL ,
PAGE_READONLY , 0 , 0 , NULL ) ;
if ( ! hFileMapping )
{
dwError = GetLastError ( ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
CloseHandle ( hFile ) ;
SetLastError ( dwError ) ;
return FALSE ;
}
// Map a view of the the file.
pView = MapViewOfFile ( hFileMapping , FILE_MAP_READ , 0 , 0 , 0 ) ;
if ( ! pView )
{
dwError = GetLastError ( ) ;
if ( hFileMapping )
CloseHandle ( hFileMapping ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
CloseHandle ( hFile ) ;
SetLastError ( dwError ) ;
return FALSE ;
}
// The DOS header begins at byte 0.
pDosExeHdr = ( PIMAGE_DOS_HEADER ) pView ;
// Check to make sure the file has a DOS EXE header.
if ( pDosExeHdr - > e_magic ! = IMAGE_DOS_SIGNATURE )
{
if ( pView )
UnmapViewOfFile ( pView ) ;
if ( hFileMapping )
CloseHandle ( hFileMapping ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
CloseHandle ( hFile ) ;
SetLastError ( ERROR_BAD_FORMAT ) ;
return FALSE ;
}
// Find the beginning of the NT header at offset e_lfanew.
2010-03-27 19:20:16 +00:00
pNtExeHdr = ( PIMAGE_NT_HEADERS ) ( ( ULONG_PTR ) pView
+ pDosExeHdr - > e_lfanew ) ;
2007-04-24 14:24:18 +00:00
// Check to make sure the file is a VxD.
if ( ( DWORD ) pNtExeHdr - > Signature ! = IMAGE_VXD_SIGNATURE )
{
if ( pView )
UnmapViewOfFile ( pView ) ;
if ( hFileMapping )
CloseHandle ( hFileMapping ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
CloseHandle ( hFile ) ;
SetLastError ( ERROR_BAD_FORMAT ) ;
return FALSE ;
}
// The LE header begins at the same place as the NT header.
pLEHdr = ( PIMAGE_VXD_HEADER ) pNtExeHdr ;
// e32_winreslen contains the size of the VxD's version resource.
if ( pLEHdr - > e32_winreslen = = 0 ) {
* lpdwLen = 0 ;
if ( pView )
UnmapViewOfFile ( pView ) ;
if ( hFileMapping )
CloseHandle ( hFileMapping ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
CloseHandle ( hFile ) ;
SetLastError ( ERROR_RESOURCE_DATA_NOT_FOUND ) ;
return FALSE ;
}
// e32_winresoff contains the offset of the resource in the VxD.
2010-03-27 19:20:16 +00:00
pVerRes = ( VXD_VERSION_RESOURCE * ) ( ( ULONG_PTR ) pView
+ pLEHdr - > e32_winresoff ) ;
2007-04-24 14:24:18 +00:00
dwSize = pVerRes - > dwResSize ;
pRawRes = & ( pVerRes - > bVerData ) ;
// Make sure the supplied buffer is large enough for the resource.
if ( ( lpData = = NULL ) | | ( * lpdwLen < dwSize ) ) {
* lpdwLen = dwSize ;
if ( pView )
UnmapViewOfFile ( pView ) ;
if ( hFileMapping )
CloseHandle ( hFileMapping ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
CloseHandle ( hFile ) ;
SetLastError ( ERROR_INSUFFICIENT_BUFFER ) ;
return FALSE ;
}
// Zero the passed buffer and copy the resource into it.
ZeroMemory ( lpData , * lpdwLen ) ;
CopyMemory ( lpData , pRawRes , dwSize ) ;
* lpdwLen = dwSize ;
// Clean up resources.
if ( pView )
UnmapViewOfFile ( pView ) ;
if ( hFileMapping )
CloseHandle ( hFileMapping ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
CloseHandle ( hFile ) ;
SetLastError ( 0 ) ;
return TRUE ;
}
2010-03-24 17:22:56 +00:00
static DWORD GetVxdVersionInfoSize ( LPCTSTR szFile )
2007-04-24 14:24:18 +00:00
{
DWORD dwResult = 0 ;
// Call GetVxdVersion() with NULL for the pointer to the buffer.
if ( ! GetVxdVersion ( szFile , & dwResult , NULL ) )
{
DWORD dwError = GetLastError ( ) ;
// GetVxdVersion() will fail with ERROR_INSUFFICIENT_BUFFER and
// the required buffer size will be returned in dwResult.
2010-03-27 19:20:16 +00:00
if ( dwError = = ERROR_INSUFFICIENT_BUFFER )
2007-04-24 14:24:18 +00:00
{
SetLastError ( 0 ) ;
return dwResult ;
}
}
// The following line is never executed.
return 0 ;
}
2010-03-24 17:22:56 +00:00
static BOOL GetVxdVersionInfo ( LPCTSTR szFile , DWORD dwLen , LPVOID lpData )
2007-04-24 14:24:18 +00:00
{
return GetVxdVersion ( szFile , & dwLen , lpData ) ;
}
# endif //_WIN32
2010-03-24 17:22:56 +00:00
static bool GetDLLVersionFromVXD ( const tstring & filepath , DWORD & high , DWORD & low )
2007-04-24 14:24:18 +00:00
{
bool found = false ;
# ifdef _WIN32
DWORD verSize = GetVxdVersionInfoSize ( filepath . c_str ( ) ) ;
if ( verSize )
{
void * buf = ( void * ) GlobalAlloc ( GPTR , verSize ) ;
if ( buf )
{
UINT uLen ;
VS_FIXEDFILEINFO * pvsf ;
2010-03-24 17:22:56 +00:00
if ( GetVxdVersionInfo ( filepath . c_str ( ) , verSize , buf ) & & VerQueryValue ( buf , _T ( " \\ " ) , ( void * * ) & pvsf , & uLen ) )
2007-04-24 14:24:18 +00:00
{
low = pvsf - > dwFileVersionLS ;
high = pvsf - > dwFileVersionMS ;
found = true ;
}
GlobalFree ( buf ) ;
}
}
# endif
return found ;
}
2010-03-24 17:22:56 +00:00
bool GetDLLVersion ( const tstring & filepath , DWORD & high , DWORD & low )
2007-04-24 14:06:50 +00:00
{
if ( GetDLLVersionUsingAPI ( filepath , high , low ) )
return true ;
if ( GetDLLVersionUsingRE ( filepath , high , low ) )
return true ;
2007-04-24 14:24:18 +00:00
if ( GetDLLVersionFromVXD ( filepath , high , low ) )
return true ;
2007-04-24 14:06:50 +00:00
return false ;
}
2011-12-05 23:44:26 +00:00
bool Platform_SupportsUTF8Conversion ( )
{
static unsigned char cached = - 1 ;
if ( - 1 = = cached ) cached = ! ! IsValidCodePage ( CP_UTF8 ) ;
return cached ! = 0 ;
}