2006-10-28 19:45:02 +00:00
/*
* util . cpp
*
* This file is a part of NSIS .
*
2021-01-01 20:27:52 +00:00
* Copyright ( C ) 1999 - 2021 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
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"
2019-02-10 20:45:40 +00:00
# include "BinInterop.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>
2013-12-08 14:34:38 +00:00
# include <stdlib.h>
# include <limits.h>
# ifdef _UNICODE
# include <wchar.h>
# endif
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 ;
2016-11-22 21:17:00 +00:00
extern FILE * g_output , * g_errout ;
2002-08-02 10:01:35 +00:00
2017-10-21 01:29:11 +00:00
2017-10-19 14:16:09 +00:00
# ifdef _WIN32
2017-10-21 01:29:11 +00:00
static char * CreateMappedFileView ( LPCTSTR Path , DWORD FAccess , DWORD FShare , DWORD FMode , DWORD PProtect , DWORD MAccess )
2017-10-19 14:16:09 +00:00
{
char * pView = NULL , restoreGLE = false ;
2017-10-21 01:29:11 +00:00
HANDLE hFile = CreateFile ( Path , FAccess , FShare , NULL , FMode , 0 , NULL ) ;
2017-10-19 14:16:09 +00:00
if ( hFile = = INVALID_HANDLE_VALUE ) return pView ;
HANDLE hMap = CreateFileMapping ( hFile , NULL , PProtect , 0 , 0 , NULL ) ;
if ( hMap ! = INVALID_HANDLE_VALUE )
{
CloseHandle ( hFile ) ;
if ( ( pView = ( char * ) MapViewOfFile ( hMap , MAccess , 0 , 0 , 0 ) ) )
{
CloseHandle ( hMap ) ;
}
else
{
DWORD error = restoreGLE ? GetLastError ( ) : 0 ;
CloseHandle ( hMap ) ;
if ( restoreGLE ) SetLastError ( error ) ;
}
}
else
{
DWORD error = restoreGLE ? GetLastError ( ) : 0 ;
CloseHandle ( hFile ) ;
if ( restoreGLE ) SetLastError ( error ) ;
}
return pView ;
}
2017-10-21 01:29:11 +00:00
# else
# include <sys/stat.h>
# include <sys/mman.h>
static char * CreateMappedFileView ( const TCHAR * Path , const char * FMode , int PProtect , int MFlags , size_t & FSize )
{
char * pView = NULL ;
FILE * pFile = FOPEN ( Path , FMode ) ;
if ( pFile )
{
struct stat fs ;
int fd = fileno ( pFile ) , toobig ;
if ( - 1 ! = fd & & 0 = = fstat ( fd , & fs ) )
{
FSize = ( size_t ) fs . st_size , toobig = sizeof ( size_t ) < sizeof ( fs . st_size ) & & ( INT64 ) FSize ! = fs . st_size ;
void * p = ! toobig ? mmap ( NULL , FSize , PProtect , MFlags , fd , 0 ) : MAP_FAILED ;
if ( p ! = MAP_FAILED ) pView = ( char * ) p ;
}
fclose ( pFile ) ;
}
return pView ;
}
2017-10-19 14:16:09 +00:00
# endif //~ _WIN32
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
}
2014-05-19 19:23:06 +00:00
size_t my_strncpy ( TCHAR * Dest , const TCHAR * Src , size_t cchMax )
2013-03-07 21:25:35 +00:00
{
// Dest and Src must be valid, Dest is always \0 terminated.
2014-05-19 19:23:06 +00:00
// Returns number of TCHARs copied to Dest (not counting \0); min(strlen(Src),cchMax-1).
size_t cch = 0 ;
2017-05-03 12:08:09 +00:00
if ( cchMax ) for ( TCHAR c ; - - cchMax ; ) { if ( ! ( c = Src [ cch ] ) ) break ; Dest [ cch + + ] = c ; }
2014-05-19 19:23:06 +00:00
Dest [ cch ] = _T ( ' \0 ' ) ;
2013-03-07 21:25:35 +00:00
return cch ;
}
2010-05-04 22:28:53 +00:00
2017-10-04 23:40:45 +00:00
size_t my_strftime ( TCHAR * s , size_t max , const TCHAR * fmt , const struct tm * tm )
{
return _tcsftime ( s , max , fmt , tm ) ;
}
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 ;
2019-02-10 20:45:40 +00:00
signed char hdr [ 14 + 124 ] , retval = - 2 ;
size_t size = fread ( hdr , 1 , sizeof ( hdr ) , f ) ;
GENERICIMAGEINFO info ;
2021-06-25 20:44:37 +00:00
if ( IsBMPFile ( hdr , size , & info ) & & 0 = = fseek ( f , 0 , SEEK_SET ) & & LoadImageCanLoadFileFromResource ( hdr , size ) )
2019-02-10 20:45:40 +00:00
{
if ( ( width & & width ! = ( int ) info . Width ) | | ( height & & height ! = ( int ) info . Height ) )
retval = - 3 ;
else if ( maxbpp & & maxbpp < info . BPP )
retval = - 4 ;
else if ( re - > UpdateResource ( RT_BITMAP , id , NSIS_DEFAULT_LANG , f , CResourceEditor : : TM_AUTO ) )
retval = 0 ;
2002-08-02 10:01:35 +00:00
}
fclose ( f ) ;
2013-03-19 02:11:37 +00:00
return retval ;
2002-08-02 10:01:35 +00:00
}
2019-02-10 20:45:40 +00:00
tstring make_friendly_resource_path ( const TCHAR * rt , const TCHAR * rn , LANGID rl )
{
tstring s = _T ( " " ) ;
TCHAR buf [ 42 ] , sep = _T ( ' \\ ' ) ;
s + = IS_INTRESOURCE ( rt ) ? ( wsprintf ( buf , _T ( " #%d " ) , ( int ) ( size_t ) rt ) , buf ) : rt ;
s + = sep ;
s + = IS_INTRESOURCE ( rn ) ? ( wsprintf ( buf , _T ( " #%d " ) , ( int ) ( size_t ) rn ) , buf ) : rn ;
s + = sep ;
if ( rl = = CResourceEditor : : ALLLANGID )
s + = _T ( " All " ) ;
else
s + = ( wsprintf ( buf , _T ( " %d " ) , ( int ) ( size_t ) rl ) , buf ) ;
return s ;
}
2004-03-29 20:21:00 +00:00
# ifndef _WIN32
2013-12-08 14:34:38 +00:00
void PathConvertWinToPosix ( char * p ) ;
BOOL IsDBCSLeadByteEx ( unsigned int CodePage , unsigned char TestChar )
{
if ( CP_UTF8 = = CodePage ) return false ; //blogs.msdn.com/b/michkap/archive/2007/04/19/2190207.aspx
const char buf [ ] = { ( char ) TestChar , ' a ' , ' b ' , ' \0 ' } ; // Untested and probably not the best way to do this!
return CharNextExA ( CodePage , buf , 0 ) > & buf [ 1 ] ;
}
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
}
2017-05-03 12:08:09 +00:00
return const_cast < TCHAR * > ( s ) ;
2004-03-29 20:21:00 +00:00
}
2012-03-01 21:06:14 +00:00
char * CharNextA ( const char * s ) {
2021-07-27 18:56:42 +00:00
int l = 0 , mbl ;
2004-03-29 20:21:00 +00:00
if ( s & & * s )
2021-07-27 18:56:42 +00:00
mbl = mblen ( s , MB_CUR_MAX ) , l = max ( 1 , mbl ) ;
2017-05-03 12:08:09 +00:00
return const_cast < char * > ( s + l ) ;
2012-03-01 21:06:14 +00:00
}
2013-12-08 14:34:38 +00:00
wchar_t * CharNextW ( const wchar_t * s ) {
2017-05-03 12:08:09 +00:00
if ( sizeof ( * s ) = = 2 & & IsLeadSurrogateUTF16 ( * s ) ) + + s ; //BUGBUG: This assumes that 16bit wchar_t == UTF16
// else if (...) BUGBUG: Is this the best we can do? What about combining characters/diacritics etc?
return const_cast < wchar_t * > ( 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 ) {
2013-12-08 14:34:38 +00:00
// blogs.msdn.com/b/michkap/archive/2007/04/19/2190207.aspx implies that
// CharNextExA uses IsDBCSLeadByteEx, should we do the same?
const char * orglocct = NSISRT_setlocale_wincp ( LC_CTYPE , codepage ) , * np ;
2007-07-18 19:18:00 +00:00
int len = mblen ( s , strlen ( s ) ) ;
2013-12-08 14:34:38 +00:00
if ( len > 0 ) np = s + len ; else np = s + 1 ;
2012-03-01 21:06:14 +00:00
setlocale ( LC_CTYPE , orglocct ) ;
2017-05-03 12:08:09 +00:00
return const_cast < char * > ( np ) ;
2007-07-18 19:18:00 +00:00
}
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 ) ;
2013-12-08 14:34:38 +00:00
int res = _vsntprintf ( s , 1024 + 1 , format , val ) ;
if ( res > = 0 ) s [ res ] = _T ( ' \0 ' ) ;
va_end ( val ) ;
return res ;
}
2014-10-05 21:52:03 +00:00
static char g_nrt_iconv_narrowlocbuf [ 50 ] , * g_nrt_iconv_narrowloc = 0 ;
2013-12-08 14:34:38 +00:00
# define setlocale_ACP(cat) setlocale((cat), "")
# define iconv_ACP g_nrt_iconv_narrowloc
# define setlocale_OEM(cat) NSISRT_setlocale_wincp((cat), 1252)
# define iconv_OEM "CP1252"
# ifdef HAVE_LANGINFO_H // BUGBUG: scons needs to check for HAVE_LANGINFO_H and HAVE_NL_LANGINFO support?
# include <langinfo.h>
# endif
2016-11-23 15:42:20 +00:00
bool NSISRT_Initialize ( ) // Init function for POSIX
2013-12-08 14:34:38 +00:00
{
iconvdescriptor id ;
g_nrt_iconv_narrowloc = const_cast < char * > ( " " ) ; // Use "" and not "char", "char" is a GNU extension?
if ( ! id . Open ( " wchar_t " , g_nrt_iconv_narrowloc ) )
{
unsigned int cchmax = COUNTOF ( g_nrt_iconv_narrowlocbuf ) ;
const char * tmp = " " ;
# ifdef HAVE_NL_LANGINFO
tmp = nl_langinfo ( CODESET ) ; // TODO: Use libcharset or locale_charset if possible
if ( strlen ( tmp ) > = cchmax ) tmp = " " ;
# endif
strcpy ( g_nrt_iconv_narrowloc = g_nrt_iconv_narrowlocbuf , tmp ) ;
if ( ! id . Open ( " wchar_t " , g_nrt_iconv_narrowloc ) )
{
// Unable to determine the iconv narrow string code, UTF-8 is the best we can do
create_code_page_string ( g_nrt_iconv_narrowloc , cchmax , CP_UTF8 ) ;
}
}
2017-04-14 14:17:39 +00:00
return nsis_iconv_get_host_endian_ucs4_code ( ) & & IsValidCodePage ( NSISRT_GetASCIICodepage ( ) ) ;
2013-12-08 14:34:38 +00:00
}
const char * NSISRT_setlocale_wincp ( int cat , unsigned int cp )
{
if ( cp < = 1 ) return CP_ACP = = cp ? setlocale_ACP ( cat ) : setlocale_OEM ( cat ) ;
char buf [ 40 ] ;
const char * p , * p1 = 0 , * p2 = 0 ;
sprintf ( buf , " .CP%u " , cp ) ;
p = setlocale ( cat , & buf [ 1 ] ) ; // "CP%u"
if ( ! p ) p = setlocale ( cat , buf ) ; // ".CP%u" this is the format used by MSVCRT?
if ( ! p )
{
switch ( cp ) // This list is probably incomplete
{
case 932 : p1 = " SJIS " ; break ; // Not an exact match but CP932 already failed, this is the best we can do
case 936 : p1 = " EUCCN " , p2 = " euc-CN " ; break ;
case 949 : p1 = " EUCKR " , p2 = " euc-KR " ; break ;
case 950 : p1 = " Big5 " ; break ;
case 20866 : p1 = " KOI8-R " ; break ;
case 20932 : p1 = " EUCJP " , p2 = " euc-JP " ; break ;
case 65001 : p1 = " UTF-8 " , p2 = " utf8 " ; break ;
default :
if ( cp > = 28591 & & cp < = 28599 ) sprintf ( buf , " ISO-8859-%u " , cp - 28590 ) , p1 = buf ;
if ( cp = = 28603 | | cp = = 28605 ) sprintf ( buf , " ISO-8859-%u " , ( cp - 28600 ) + 10 ) , p1 = buf ;
}
if ( ! ( p = setlocale ( cat , p1 ) ) ) p = setlocale ( cat , p2 ) ;
}
return p ;
}
wchar_t * NSISRT_mbtowc ( const char * Str )
{
const char * orglocct = setlocale ( LC_CTYPE , " " ) ;
wchar_t * d = 0 ;
const char * s = Str ;
size_t cch = mbsrtowcs ( 0 , & s , 0 , 0 ) ;
if ( ( size_t ) - 1 ! = cch & & ( d = ( wchar_t * ) malloc ( + + cch * sizeof ( wchar_t ) ) ) )
{
cch = mbsrtowcs ( d , & Str , cch , 0 ) ;
if ( ( size_t ) - 1 = = cch ) { NSISRT_free ( d ) ; d = 0 ; }
}
if ( ! errno ) errno = ENOMEM ;
setlocale ( LC_CTYPE , orglocct ) ;
return d ;
}
char * NSISRT_wctomb ( const wchar_t * Str )
{
const char * orglocct = setlocale ( LC_CTYPE , " " ) ;
char * d = 0 ;
const wchar_t * s = Str ;
errno = 0 ;
size_t cb = wcsrtombs ( 0 , & s , 0 , 0 ) ;
if ( ( size_t ) - 1 ! = cb & & ( d = ( char * ) malloc ( + + cb ) ) )
{
cb = wcsrtombs ( d , & Str , cb , 0 ) ;
if ( ( size_t ) - 1 = = cb ) { NSISRT_free ( d ) ; d = 0 ; }
}
if ( ! errno ) errno = ENOMEM ;
setlocale ( LC_CTYPE , orglocct ) ;
return d ;
}
char * NSISRT_wctombpath ( const wchar_t * Path )
{
char * p = NSISRT_wctomb ( Path ) ;
if ( p ) PathConvertWinToPosix ( p ) ;
return p ;
}
char * NSISRT_ttombpath ( const TCHAR * Path )
{
# ifdef _UNICODE
return NSISRT_wctombpath ( Path ) ;
# else
char * p = _tcsdup ( Path ) ;
if ( p ) PathConvertWinToPosix ( p ) ; else errno = ENOMEM ;
return p ;
# endif
}
# include <wctype.h>
int _wcsnicmp ( const wchar_t * a , const wchar_t * b , size_t n )
{
// Note: Behavior depends on the LC_CTYPE category of the current locale.
# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
return wcsncasecmp ( a , b , n ) ;
# else
int diff = 0 ;
for ( ; n - - ; + + a , + + b )
if ( ( diff = ( int ) towlower ( * a ) - ( int ) towlower ( * b ) ) | | ! * a ) break ;
return diff ;
# endif
}
int _wcsicmp ( const wchar_t * a , const wchar_t * b )
{
return _wcsnicmp ( a , b , ( size_t ) - 1 ) ;
}
long _wtol ( const wchar_t * s ) { return wcstol ( s , 0 , 10 ) ; }
int _wtoi ( const wchar_t * s )
{
errno = 0 ;
long int r = _wtol ( s ) ;
if ( errno ) r = 0 ;
if ( LONG_MIN = = r ) r = INT_MIN ;
if ( LONG_MAX = = r ) r = INT_MAX ;
return ( int ) r ;
}
int _swprintf ( wchar_t * d , const wchar_t * f , . . . )
{
va_list val ;
va_start ( val , f ) ;
int res = _vsnwprintf ( d , INT_MAX / sizeof ( * d ) , f , 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-12-08 14:34:38 +00:00
wchar_t * _wcsdup ( const wchar_t * s )
{
wchar_t * d = ( wchar_t * ) malloc ( ( wcslen ( s ) + 1 ) * sizeof ( wchar_t ) ) ;
if ( d ) wcscpy ( d , s ) ;
return d ;
}
wchar_t * _wgetenv ( const wchar_t * wname )
{
mbstate_t mbs ;
memset ( & mbs , 0 , sizeof ( mbs ) ) ;
char * nval , * nval2 , nname [ 200 ] ; // Hopefully this is enough
size_t cbnn = wcsrtombs ( nname , & wname , sizeof ( nname ) , & mbs ) ;
if ( ( size_t ) - 1 = = cbnn | | ! ( nval = getenv ( nname ) ) ) return NULL ;
static wchar_t * g_wval = 0 ; // Not thread safe!
for ( unsigned int cch = 200 ; ; cch * = 2 )
{
if ( ! ( g_wval = ( wchar_t * ) realloc ( g_wval , cch * sizeof ( wchar_t ) ) ) ) break ;
nval2 = nval ;
memset ( & mbs , 0 , sizeof ( mbs ) ) ;
size_t cchwv = mbsrtowcs ( g_wval , const_cast < const char * * > ( & nval2 ) , cch , & mbs ) ;
if ( ( size_t ) - 1 = = cchwv ) return NULL ;
if ( ! nval2 ) return g_wval ;
}
errno = ENOMEM ;
return 0 ;
}
int _wremove ( const wchar_t * Path )
{
const char * path = NSISRT_wctomb ( Path ) ; // Caller should have converted to POSIX path
if ( ! path ) return - 1 ;
const int retval = remove ( path ) ;
NSISRT_free ( path ) ;
return retval ;
}
int _wchdir ( const wchar_t * Path )
{
const char * path = NSISRT_wctomb ( Path ) ; // Caller should have converted to POSIX path
if ( ! path ) return - 1 ;
const int retval = chdir ( path ) ;
NSISRT_free ( path ) ;
return retval ;
}
# include <sys/types.h>
# include <sys/stat.h>
int _wstat ( const wchar_t * Path , struct stat * pS )
{
const char * path = NSISRT_wctomb ( Path ) ; // Caller should have converted to POSIX path
if ( ! path ) return - 1 ;
const int retval = stat ( path , pS ) ;
NSISRT_free ( path ) ;
return retval ;
}
2014-01-21 14:13:00 +00:00
# ifdef _UNICODE
2013-12-08 14:34:38 +00:00
static int NSISRT_wsystem ( const wchar_t * wcmd )
{
if ( ! wcmd ) return system ( NULL ) ;
// NOTE: Only the first drive in the path will be converted to posix style (c:\foo d:\bar > /c/foo d:/bar)
const char * cmd = NSISRT_wctombpath ( wcmd ) ;
if ( ! cmd ) return - 1 ;
const int retval = system ( cmd ) ;
NSISRT_free ( cmd ) ;
return retval ;
}
2014-01-21 14:13:00 +00:00
# endif
2013-12-08 14:34:38 +00:00
const char * nsis_iconv_get_host_endian_ucs4_code ( )
{
static const char * ucs4 = 0 ;
if ( ! ucs4 )
{
iconvdescriptor id ;
# define NRT_TMP_IGHEUC(s) if (id.Open("wchar_t", (s))) return ucs4 = (s)
NRT_TMP_IGHEUC ( " UCS-4-INTERNAL " ) ;
NRT_TMP_IGHEUC ( Platform_IsBigEndian ( ) ? " UCS-4BE " : " UCS-4LE " ) ;
NRT_TMP_IGHEUC ( Platform_IsBigEndian ( ) ? " UTF-32BE " : " UTF-32LE " ) ;
# undef NRT_TMP_IGHEUC
}
return ucs4 ;
}
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 ;
}
2013-12-08 14:34:38 +00:00
const unsigned short CODEPAGESTR_MAXLEN = 50 ; // Should be plenty
void create_code_page_string ( TCHAR * buf , size_t len , UINT code_page )
{
2014-10-05 21:52:03 +00:00
if ( ! g_nrt_iconv_narrowloc ) NSISRT_Initialize ( ) ; // For winchar.cpp unit test
2011-12-05 23:44:26 +00:00
switch ( code_page )
{
2015-09-17 14:30:07 +00:00
case CP_ACP : _sntprintf ( buf , len , _T ( " % " ) NPRIns , iconv_ACP ) ; return ;
case CP_OEMCP : _sntprintf ( buf , len , _T ( " % " ) NPRIns , iconv_OEM ) ; return ;
2013-12-08 14:34:38 +00:00
case CP_UTF8 : _sntprintf ( buf , len , _T ( " UTF-8 " ) ) ; return ;
2013-04-03 22:46:17 +00:00
case 1200 : // UTF16LE
case 1201 : // UTF16BE
2013-12-08 14:34:38 +00:00
_sntprintf ( buf , len , _T ( " UTF-16%cE " ) , 1200 = = code_page ? ' L ' : ' B ' ) ;
2013-04-03 22:46:17 +00:00
return ;
2011-12-05 23:44:26 +00:00
}
2014-05-05 02:27:48 +00:00
_sntprintf ( buf , len , _T ( " CP%d//TRANSLIT " ) , code_page ) ;
2004-12-11 16:06:17 +00:00
}
2013-12-08 14:34:38 +00:00
# ifdef _UNICODE
void create_code_page_string ( char * buf , size_t len , UINT code_page )
{
TCHAR t [ CODEPAGESTR_MAXLEN ] ;
create_code_page_string ( t , COUNTOF ( t ) , code_page ) ;
RawTStrToASCII ( t , buf , len ) ;
}
# endif
2004-12-11 16:06:17 +00:00
2013-12-08 14:34:38 +00:00
int WideCharToMultiByte ( UINT CodePage , DWORD dwFlags , const wchar_t * lpWideCharStr ,
2004-12-11 16:06:17 +00:00
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
2013-12-08 14:34:38 +00:00
char cp [ CODEPAGESTR_MAXLEN ] ;
create_code_page_string ( cp , COUNTOF ( cp ) , CodePage ) ;
2013-03-07 21:25:35 +00:00
iconv_t cd = iconv_open ( cp , " wchar_t " ) ;
2013-12-08 14:34:38 +00:00
if ( cd = = ( iconv_t ) - 1 ) return 0 ;
if ( cchWideChar < 0 ) cchWideChar = ( int ) wcslen ( lpWideCharStr ) + 1 ;
if ( cbMultiByte = = 0 ) cbMultiByte = sizeof ( buffer ) , lpMultiByteStr = buffer ;
2004-12-11 16:06:17 +00:00
2013-12-08 14:34:38 +00:00
char * in = ( char * ) lpWideCharStr , * out = lpMultiByteStr ;
size_t inbytes = cchWideChar * sizeof ( wchar_t ) , outbytes = cbMultiByte ;
2004-12-11 16:06:17 +00:00
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 ,
2013-12-08 14:34:38 +00:00
int cbMultiByte , wchar_t * lpWideCharStr , int cchWideChar ) {
static wchar_t buffer [ 4096 ] ; // BUGBUG: Should this be 4*NSIS_MAX_STRLEN for large string build?
2004-12-11 16:06:17 +00:00
2013-12-08 14:34:38 +00:00
char cp [ CODEPAGESTR_MAXLEN ] ;
create_code_page_string ( cp , COUNTOF ( cp ) , CodePage ) ;
2013-03-07 21:25:35 +00:00
iconv_t cd = iconv_open ( " wchar_t " , cp ) ;
2013-12-08 14:34:38 +00:00
if ( cd = = ( iconv_t ) - 1 ) return 0 ;
if ( cbMultiByte < 0 ) cbMultiByte = strlen ( lpMultiByteStr ) + 1 ;
if ( cchWideChar = = 0 ) cchWideChar = sizeof ( buffer ) , lpWideCharStr = buffer ;
2004-12-11 16:06:17 +00:00
2013-12-08 14:34:38 +00:00
char * in = ( char * ) lpMultiByteStr , * out = ( char * ) lpWideCharStr ;
size_t inbytes = cbMultiByte , outbytes = cchWideChar * sizeof ( wchar_t ) ;
2004-12-11 16:06:17 +00:00
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 ) ;
2013-12-08 14:34:38 +00:00
return cchWideChar - ( outbytes / sizeof ( wchar_t ) ) ;
2004-12-11 16:06:17 +00:00
}
2007-07-18 19:26:16 +00:00
BOOL IsValidCodePage ( UINT CodePage )
{
2013-12-08 14:34:38 +00:00
char cp [ CODEPAGESTR_MAXLEN ] ;
create_code_page_string ( cp , COUNTOF ( cp ) , CodePage ) ;
iconv_t cd = iconv_open ( " wchar_t " , cp ) ;
if ( cd = = ( iconv_t ) - 1 ) return FALSE ;
2007-07-18 19:26:16 +00:00
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 ) ;
2013-12-08 14:34:38 +00:00
/* Replace drive letter X: by /x */
if ( len > = 2 & & ' : ' = = p [ 1 ] ) p [ 1 ] = ( char ) tolower ( ( int ) p [ 0 ] ) , p [ 0 ] = ' / ' ;
do if ( ' \\ ' = = * p ) * p = ' / ' ; while ( * ( p = CharNextA ( p ) ) ) ;
2012-03-01 21:06:14 +00:00
}
# endif
void PathConvertWinToPosix ( TCHAR * p )
{
if ( _T ( ' \" ' ) = = * p ) + + p ; // Skip opening quote if any (For !system)
size_t len = _tcsclen ( p ) ;
2013-12-08 14:34:38 +00:00
/* Replace drive letter X: by /x */
if ( len > = 2 & & _T ( ' : ' ) = = p [ 1 ] ) p [ 1 ] = ( TCHAR ) tolower ( ( int ) p [ 0 ] ) , p [ 0 ] = _T ( ' / ' ) ;
do if ( _T ( ' \\ ' ) = = * p ) * p = _T ( ' / ' ) ; while ( * ( p = CharNext ( p ) ) ) ;
2012-03-01 21:06:14 +00:00
}
2013-12-08 14:34:38 +00:00
# define MY_ERROR_MSG(x) {if (g_display_errors) {PrintColorFmtMsg_ERR(_T("%") NPRIs, 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 ) ;
2017-05-03 12:08:09 +00:00
if ( ! converted_path )
2012-03-01 21:06:14 +00:00
{
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
{
2013-12-08 14:34:38 +00:00
# ifndef _UNICODE
int result = open ( pathname , flags ) ;
# else
char * nativepath = NSISRT_ttombpath ( pathname ) ;
if ( ! nativepath ) return - 1 ;
int result = open ( nativepath , flags ) ;
NSISRT_free ( nativepath ) ;
# endif
2004-08-20 15:40:38 +00:00
return result ;
}
2017-10-19 14:16:09 +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
2013-12-08 14:34:38 +00:00
char * nativepath = NSISRT_wctombpath ( path ) ;
if ( nativepath )
2012-03-01 21:06:14 +00:00
{
2013-12-08 14:34:38 +00:00
f = fopen ( nativepath , mode ) ;
NSISRT_free ( nativepath ) ;
2012-03-01 21:06:14 +00:00
}
# endif
# endif
return f ;
2004-08-20 15:40:38 +00:00
}
2012-03-01 21:06:14 +00:00
2017-10-05 18:11:03 +00:00
# if (defined(_MSC_VER) && (_MSC_VER >= 1200)) || defined(__MINGW32__)
# include <io.h>
static UINT64 get_file_size64 ( FILE * f )
2017-10-04 23:40:45 +00:00
{
2017-10-05 18:11:03 +00:00
INT64 s = _filelengthi64 ( _fileno ( f ) ) ; // Could also use _get_osfhandle+GetFileSize64
return ( INT64 ) - 1L ! = s ? s : invalid_file_size64 ;
}
# endif
# include <sys/types.h>
# include <sys/stat.h>
UINT32 get_file_size32 ( FILE * f )
{
UINT32 result = invalid_file_size32 ;
# if (defined(_MSC_VER) && (_MSC_VER >= 1200)) || defined(__MINGW32__)
UINT64 size64 = get_file_size64 ( f ) ;
if ( invalid_file_size64 ! = size64 & & size64 < = 0xffffffffUL )
result = ( UINT32 ) size64 ;
# elif _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
struct stat st ;
2017-10-21 01:41:27 +00:00
if ( 0 = = fstat ( fileno ( f ) , & st ) & & st . st_size < = ( sizeof ( st . st_size ) > = 8 ? ( off_t ) 0xffffffffUL : LONG_MAX ) )
2017-10-05 18:11:03 +00:00
result = ( UINT32 ) st . st_size ;
# else
2017-10-04 23:40:45 +00:00
long cb , restoreseek = true ;
fpos_t orgpos ;
2017-10-05 18:11:03 +00:00
if ( ! restoreseek | | 0 = = fgetpos ( f , & orgpos ) )
if ( 0 = = fseek ( f , 0 , SEEK_END ) ) // Not fully portable!
if ( ( cb = ftell ( f ) ) ! = - 1L ) // This might not be correct for files in text mode!
if ( ! restoreseek | | 0 = = fsetpos ( f , & orgpos ) )
2017-10-04 23:40:45 +00:00
result = cb ;
2017-10-05 18:11:03 +00:00
# endif
2017-10-04 23:40:45 +00:00
return result ;
}
BYTE * alloc_and_read_file ( FILE * f , unsigned long & size )
{
BYTE * result = 0 , * mem = 0 ;
if ( ! f ) return result ;
2017-10-05 18:11:03 +00:00
UINT32 size32 = get_file_size32 ( f ) ;
mem = ( invalid_file_size32 ! = size32 ) ? ( BYTE * ) malloc ( size = size32 ) : 0 ;
2017-10-04 23:40:45 +00:00
if ( mem )
if ( 0 = = fseek ( f , 0 , SEEK_SET ) )
if ( fread ( mem , 1 , size , f ) = = size )
result = mem , mem = 0 ;
free ( mem ) ;
return result ;
}
BYTE * alloc_and_read_file ( const TCHAR * filepath , unsigned long & size )
{
BYTE * result = 0 ;
FILE * f = FOPEN ( filepath , ( " rb " ) ) ;
if ( f )
{
result = alloc_and_read_file ( f , size ) ;
fclose ( f ) ;
}
return result ;
2004-08-18 16:14:44 +00:00
}
2004-09-30 20:25:33 +00:00
2017-10-19 14:16:09 +00:00
void close_file_view ( FILEVIEW & mmfv )
{
# ifdef _WIN32
if ( mmfv . base ) UnmapViewOfFile ( mmfv . base ) ;
# else
2017-10-21 01:29:11 +00:00
if ( mmfv . base ) munmap ( mmfv . base , mmfv . internal ) ;
2017-10-19 14:16:09 +00:00
# endif
}
char * create_file_view_readonly ( const TCHAR * filepath , FILEVIEW & mmfv )
{
# ifdef _WIN32
return mmfv . base = CreateMappedFileView ( filepath , GENERIC_READ , FILE_SHARE_READ , OPEN_EXISTING , PAGE_READONLY , FILE_MAP_READ ) ;
# else
2017-10-21 01:29:11 +00:00
return mmfv . base = CreateMappedFileView ( filepath , " rb " , PROT_READ , MAP_SHARED , mmfv . internal ) ;
2017-10-19 14:16:09 +00:00
# endif
}
2021-08-18 13:53:50 +00:00
size_t write_octets_to_file ( const TCHAR * filename , const void * data , size_t cb )
{
FILE * hfile = FOPEN ( filename , ( " wb " ) ) ;
if ( ! hfile ) return 0 ;
size_t ret = fwrite ( data , 1 , cb , hfile ) ;
fclose ( hfile ) ;
return ret ;
}
2018-10-24 19:01:00 +00:00
TCHAR * create_tempfile_path ( )
{
TCHAR * tfpath = NULL ;
# ifdef _WIN32
TCHAR buftmpdir [ MAX_PATH ] , buf [ MAX_PATH ] ;
DWORD cch = GetTempPath ( COUNTOF ( buftmpdir ) , buftmpdir ) ;
if ( cch & & cch < COUNTOF ( buftmpdir ) & & GetTempFileName ( buftmpdir , _T ( " nst " ) , 0 , buf ) )
tfpath = _tcsdup ( buf ) ;
# else //! _WIN32
char narrowpath [ ] = ( " /tmp/makensisXXXXXX " ) ;
const mode_t org_umask = umask ( 0077 ) ;
int fd = mkstemp ( narrowpath ) ;
umask ( org_umask ) ;
if ( fd ! = - 1 )
{
# ifdef _UNICODE
assert ( NSISRT_free_is_STDC_free ( ) ) ;
tfpath = NSISRT_mbtowc ( narrowpath ) ;
# else
tfpath = _tcsdup ( narrowpath ) ;
# endif
close ( fd ) ;
}
# endif //~ _WIN32
return tfpath ;
}
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
2013-12-08 14:34:38 +00:00
TCHAR real_path [ 1024 ] , * fnpart ;
DWORD rc = GetFullPathName ( path . c_str ( ) , COUNTOF ( real_path ) , real_path , & fnpart ) ;
2004-09-30 20:25:33 +00:00
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 ) ;
2013-12-08 14:34:38 +00:00
# else // !_WIN32
tstring result ;
char * rpret = 0 , * inputpath = NSISRT_ttombpath ( path . c_str ( ) ) ;
if ( ! inputpath ) return tstring ( path ) ;
2004-10-01 19:52:56 +00:00
# ifdef PATH_MAX
2013-12-08 14:34:38 +00:00
static char buffer [ PATH_MAX ] ;
# else // !PATH_MAX
# if _POSIX_C_SOURCE >= 200809L
char * buffer = NULL ; // realpath can malloc
# else
int path_max = pathconf ( inputpath , _PC_PATH_MAX ) ;
if ( path_max < = 0 ) path_max = 4096 ;
char * buffer = ( char * ) malloc ( path_max * sizeof ( char ) ) ;
if ( buffer )
# endif
# endif // ~PATH_MAX
{
rpret = realpath ( inputpath , buffer ) ;
}
result = CtoTString ( rpret ? rpret : inputpath ) ;
2004-10-01 19:52:56 +00:00
# ifndef PATH_MAX
2013-12-08 14:34:38 +00:00
free ( rpret ? rpret : buffer ) ;
# endif
NSISRT_free ( inputpath ) ;
2004-09-30 20:25:33 +00:00
return result ;
2013-12-08 14:34:38 +00:00
# endif // ~_WIN32
2004-09-30 20:25:33 +00:00
}
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 ) ;
2013-12-08 14:34:38 +00:00
if ( last_separator_pos = = string : : npos ) return str ;
2005-08-27 19:56:00 +00:00
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 ) ;
2013-12-08 14:34:38 +00:00
if ( last_separator_pos = = tstring : : npos ) 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 ) {
2013-12-08 14:34:38 +00:00
return get_string_prefix ( path , PLATFORM_PATH_SEPARATOR_STR ) ; // BUGBUG: Windows should support "\" and "/"
2005-08-27 19:56:00 +00:00
}
2010-03-24 17:22:56 +00:00
tstring get_file_name ( const tstring & path ) {
2013-12-08 14:34:38 +00:00
return get_string_suffix ( path , PLATFORM_PATH_SEPARATOR_STR ) ; // BUGBUG: Windows should support "\" and "/"
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__
2014-07-05 00:11:17 +00:00
char 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 ) ;
2014-07-05 00:11:17 +00:00
return tstring ( CtoTString ( 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 ( " _ " ) ) ;
2017-05-03 12:08:09 +00:00
if ( envpath )
2015-05-14 20:17:14 +00:00
return get_full_path ( envpath ) ;
2006-03-15 06:51:31 +00:00
else {
2013-12-08 14:34:38 +00:00
char * path = NULL , * pathtmp ;
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 ) {
2013-12-08 14:34:38 +00:00
pathtmp = ( char * ) realloc ( path , len + 1 ) ;
2017-05-03 12:08:09 +00:00
if ( pathtmp = = NULL ) {
2006-03-15 06:51:31 +00:00
free ( path ) ;
return get_full_path ( argv0 ) ;
}
path = pathtmp ;
2013-12-08 14:34:38 +00:00
nchars = readlink ( " /proc/self/exe " , path , len ) ;
2017-05-03 12:08:09 +00:00
if ( nchars = = - 1 ) {
2006-03-15 06:51:31 +00:00
free ( path ) ;
return get_full_path ( argv0 ) ;
}
2017-05-03 12:08:09 +00:00
if ( nchars < ( int ) len ) {
2013-12-08 14:34:38 +00:00
path [ nchars ] = ' \0 ' ;
tstring result ;
result = CtoTString ( path ) ;
2006-03-15 06:51:31 +00:00
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
}
2014-07-18 16:37:08 +00:00
tstring & path_append_separator ( tstring & path )
{
tstring : : iterator ib = path . begin ( ) , ie = path . end ( ) ;
if ( ib ! = ie & & ! IsPathSeparator ( * - - ie ) )
2014-07-19 19:21:43 +00:00
path + = PLATFORM_PATH_SEPARATOR_STR ;
2014-07-18 16:37:08 +00:00
return path ;
}
tstring & path_append ( tstring & base , const TCHAR * more )
{
if ( IsPathSeparator ( * more ) ) + + more ;
return path_append_separator ( base ) + = more ;
}
2014-05-20 19:30:36 +00:00
static int PathGetDosDriveNumber ( const TCHAR * p )
{
// Note: Unlike PathGetDriveNumber(), we require a path separator after the colon.
if ( p [ 0 ] & & _T ( ' : ' ) = = p [ 1 ] & & IsAgnosticPathSeparator ( p [ 2 ] ) )
{
const TCHAR loch = p [ 0 ] | 32 ;
if ( loch > = _T ( ' a ' ) & & loch < = _T ( ' z ' ) ) return loch - _T ( ' a ' ) ;
}
return - 1 ;
}
bool IsWindowsPathRelative ( const TCHAR * p )
{
if ( _T ( ' \\ ' ) = = p [ 0 ] ) return _T ( ' \\ ' ) ! = p [ 1 ] ; // Current drive relative, not (unverified) UNC
return PathGetDosDriveNumber ( p ) < 0 ;
}
2019-10-24 22:15:30 +00:00
tstring replace_all ( const TCHAR * str , const TCHAR * find , const TCHAR * repl )
{
tstring out = str ;
for ( size_t cchF = _tcslen ( find ) , cchR = _tcslen ( repl ) , i = 0 ; ; i + = cchR )
if ( ( i = out . find ( find , i ) ) = = tstring : : npos )
return out ;
else
out . replace ( i , cchF , repl ) ;
}
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-12-08 14:34:38 +00:00
void RawTStrToASCII ( const TCHAR * in , char * out , UINT maxcch )
{
const bool empty = ! maxcch ;
for ( ; maxcch & & * in ; - - maxcch ) * out + + = ( char ) * in + + ;
if ( ! empty ) * out = 0 ;
}
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
2016-02-04 20:14:06 +00:00
* large enough to hold the formatted string .
2013-03-10 22:26:27 +00:00
*/
size_t ExpandoStrFmtVaList ( wchar_t * Stack , size_t cchStack , wchar_t * * ppMalloc , const wchar_t * FmtStr , va_list Args )
{
# ifdef _WIN32
2015-11-01 17:11:53 +00:00
static size_t qlen = INT_MAX ;
2013-07-25 22:00:53 +00:00
// For _vsnwprintf, the \0 terminator is not part of the input size
2013-12-08 14:34:38 +00:00
# if _MSC_VER < 1310
2015-11-01 17:11:53 +00:00
const bool have__vscwprintf = false ;
2013-07-25 22:00:53 +00:00
# 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
2015-11-01 17:11:53 +00:00
const bool have__vscwprintf = true ;
2013-07-25 22:00:53 +00:00
# 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
2015-11-01 17:11:53 +00:00
const size_t qlen = INT_MAX ;
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
2015-11-01 17:11:53 +00:00
int cch = have__vscwprintf ? 0 : ExpandoStrFmtVaList_vsnwprintf ( 0 , qlen = 0 , L " 333 " , Args ) ;
if ( cch ! = 3 ) cch = ExpandoStrFmtVaList_vsnwprintf ( 0 , qlen = INT_MAX , L " 333 " , Args ) ; // Is this actually necessary? Just set qlen = INT_MAX if have__vscwprintf?
2013-03-10 22:26:27 +00:00
# else
2015-11-01 17:11:53 +00:00
wchar_t testbuf [ 1 + ! 0 ] ;
int cch = ExpandoStrFmtVaList_vsnwprintf ( testbuf , COUNTOF ( testbuf ) , L " 333 " , Args ) ;
2013-03-10 22:26:27 +00:00
# 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 ) ;
2015-11-01 17:11:53 +00:00
if ( ( int ) cch < 0 )
2013-03-10 22:26:27 +00:00
{
cch = 0 ;
if ( cansizecalc ) break ; // vswprintf error, abort!
if ( msvcbackdoor )
2015-11-01 17:11:53 +00:00
cchAvail = ExpandoStrFmtVaList_vsnwprintf ( 0 , qlen , FmtStr , Args ) + 1 ;
2013-03-10 22:26:27 +00:00
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 ;
}
2014-04-05 16:50:11 +00:00
const TCHAR * GetFriendlySize ( UINT64 n , unsigned int & fn , GETFRIENDLYSIZEFLAGS f )
{
static const TCHAR * scale [ ] = {
_T ( " bytes " ) , _T ( " KiB " ) , _T ( " MiB " ) , _T ( " GiB " ) , _T ( " TiB " )
} ;
unsigned char s = 0 , accurate = f & GFSF_BYTESIFPOSSIBLE ;
while ( n > ( ( s | | ! accurate ) ? ( 1024 * 1024 ) - 1 : UINT_MAX ) ) n / = 1024 , + + s ;
fn = ( unsigned int ) n ;
if ( ! s ) return ( f & GFSF_HIDEBYTESCALE ) ? _T ( " " ) : 1 = = fn ? _T ( " byte " ) : scale [ s ] ;
return s > = COUNTOF ( scale ) ? _T ( " ? " ) : scale [ s ] ;
}
2014-06-21 23:55:24 +00:00
# ifdef _WIN32
# ifdef _UNICODE
2016-07-06 11:28:48 +00:00
int RunChildProcessRedirected ( LPCWSTR cmdprefix , LPCWSTR cmdmain , bool ForceUTF8 )
2013-05-04 13:32:47 +00:00
{
// 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.
2014-03-30 22:43:49 +00:00
UINT cp = CP_UTF8 , mbtwcf = MB_ERR_INVALID_CHARS , oemcp = GetOEMCP ( ) ;
2013-05-04 13:32:47 +00:00
errno = ENOMEM ;
2014-06-21 23:55:24 +00:00
if ( ! cmdprefix ) cmdprefix = L " " ;
2014-02-08 00:13:52 +00:00
size_t cch1 = _tcslen ( cmdprefix ) , cch2 = _tcslen ( cmdmain ) ;
2013-05-04 13:32:47 +00:00
WCHAR * cmd = ( WCHAR * ) malloc ( ( cch1 + cch2 + 1 ) * sizeof ( WCHAR ) ) ;
if ( ! cmd ) return - 1 ;
_tcscpy ( cmd , cmdprefix ) ;
_tcscat ( cmd , cmdmain ) ;
2015-09-03 11:06:18 +00:00
SECURITY_DESCRIPTOR sd = { 1 , 0 , SE_DACL_PRESENT , NULL , } ;
SECURITY_ATTRIBUTES sa = { sizeof ( sa ) , & sd , TRUE } ;
2014-03-30 22:43:49 +00:00
const UINT orgwinconcp = GetConsoleCP ( ) , orgwinconoutcp = GetConsoleOutputCP ( ) ;
2016-07-06 11:28:48 +00:00
if ( orgwinconoutcp = = oemcp & & ! ForceUTF8 ) cp = oemcp , mbtwcf = 0 ; // Bug #1092: Batch files not a fan of UTF-8
2015-09-03 11:06:18 +00:00
HANDLE hSIRd , hSIWr , hSORd , hSOWr ;
2013-05-04 13:32:47 +00:00
PROCESS_INFORMATION pi ;
2015-09-03 11:06:18 +00:00
if ( ! CreatePipe ( & hSIRd , & hSIWr , & sa , 0 ) ) // XCopy.exe does not work without a valid StdIn!
hSIRd = hSIWr = INVALID_HANDLE_VALUE ;
BOOL ok = CreatePipe ( & hSORd , & hSOWr , & sa , 0 ) ;
2013-05-04 13:32:47 +00:00
if ( ! ok )
2015-09-03 11:06:18 +00:00
hSORd = hSOWr = 0 ;
2013-05-04 13:32:47 +00:00
else
{
STARTUPINFO si = { sizeof ( si ) } ;
si . dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW ;
si . wShowWindow = SW_HIDE ;
2015-09-03 11:06:18 +00:00
si . hStdOutput = si . hStdError = hSOWr ;
si . hStdInput = hSIRd ;
2013-05-04 13:32:47 +00:00
errno = ECHILD ;
SetConsoleOutputCP ( cp ) ;
ok = CreateProcess ( 0 , cmd , 0 , 0 , TRUE , 0 , 0 , 0 , & si , & pi ) ;
2015-09-03 11:06:18 +00:00
CloseHandle ( hSOWr ) ; // We want ERROR_BROKEN_PIPE when the child is done
2013-05-04 13:32:47 +00:00
}
free ( cmd ) ;
DWORD childec = - 1 ;
if ( ok )
{
2018-01-29 14:42:13 +00:00
bool fullbuf = false , utf8 = CP_UTF8 = = cp , okt ;
2013-05-04 13:32:47 +00:00
char iobuf [ 512 ] ;
2018-06-25 21:33:30 +00:00
DWORD cbRead , cbOfs = 0 , cchwb = 0 , i ;
2013-05-04 13:32:47 +00:00
WCHAR wbuf [ 100 ] , wchbuf [ 2 + 1 ] ; // A surrogate pair + \0
for ( ; ; )
{
2015-09-03 11:06:18 +00:00
BOOL okr = ReadFile ( hSORd , iobuf + cbOfs , sizeof ( iobuf ) - cbOfs , & cbRead , 0 ) ;
2013-05-04 13:32:47 +00:00
cbRead + = cbOfs , cbOfs = 0 ;
unsigned char cbTrail , cch ;
2018-06-25 21:33:30 +00:00
for ( i = 0 ; i < cbRead ; )
2013-05-04 13:32:47 +00:00
{
cch = 0 ;
if ( utf8 )
{
okt = UTF8_GetTrailCount ( iobuf [ i ] , cbTrail ) ;
2014-03-30 22:43:49 +00:00
if ( ! okt ) // Not UTF-8? Switching to a MBCS CP
2013-05-04 13:32:47 +00:00
{
2014-03-30 22:43:49 +00:00
switchcp : cp = orgwinconoutcp , mbtwcf = 0 , utf8 = false ;
SetConsoleOutputCP ( cp = ( CP_UTF8 = = cp ? CP_ACP : cp ) ) ;
2013-05-04 13:32:47 +00:00
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 )
{
2014-03-30 22:43:49 +00:00
if ( utf8 ) goto switchcp ;
2013-05-04 13:32:47 +00:00
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 ] ;
2018-01-29 14:42:13 +00:00
fullbuf = cchwb + cch > = COUNTOF ( wbuf ) - 1 ; // cch is 1 for surrogate pairs
2013-05-04 13:32:47 +00:00
if ( ! okr | | fullbuf | | L ' \n ' = = wchbuf [ 0 ] ) // Stop on \n so \r\n conversion has enough context (...\r\n vs ...\n)
2017-10-24 13:19:00 +00:00
{ finalwrite :
2013-05-04 13:32:47 +00:00
# ifdef MAKENSIS
extern WINSIO_OSDATA g_osdata_stdout ;
WinStdIO_OStreamWrite ( g_osdata_stdout , wbuf , cchwb ) ; // Faster than _ftprintf
# else
wbuf [ cchwb ] = L ' \0 ' ;
2013-12-08 14:34:38 +00:00
_ftprintf ( g_output , _T ( " % " ) NPRIs , wbuf ) ;
2013-05-04 13:32:47 +00:00
# endif
cchwb = 0 ;
}
}
2017-10-24 13:19:00 +00:00
if ( ! okr )
{
2018-01-29 14:42:13 +00:00
if ( cchwb ) goto finalwrite ; // End of stream without a ending newline, write out the remaining data.
2017-10-24 13:19:00 +00:00
break ;
}
2013-05-04 13:32:47 +00:00
}
2017-10-24 13:19:00 +00:00
fflush ( g_output ) ;
2013-05-04 13:32:47 +00:00
WaitForSingleObject ( pi . hProcess , INFINITE ) ;
GetExitCodeProcess ( pi . hProcess , & childec ) ;
CloseHandle ( pi . hThread ) ;
CloseHandle ( pi . hProcess ) ;
}
2014-03-30 22:43:49 +00:00
SetConsoleCP ( orgwinconcp ) , SetConsoleOutputCP ( orgwinconoutcp ) ;
2015-09-03 11:06:18 +00:00
CloseHandle ( hSIRd ) , CloseHandle ( hSIWr ) ;
CloseHandle ( hSORd ) ;
2013-05-04 13:32:47 +00:00
return childec ;
}
2014-06-21 23:55:24 +00:00
# else
2016-07-06 11:28:48 +00:00
int RunChildProcessRedirected ( LPCSTR cmd , bool ForceUTF8 )
2014-06-21 23:55:24 +00:00
{
STARTUPINFO si = { sizeof ( STARTUPINFO ) , } ;
PROCESS_INFORMATION pi ;
2015-12-08 01:54:30 +00:00
if ( ! CreateProcess ( NULL , const_cast < LPSTR > ( cmd ) , NULL , NULL , FALSE , 0 , NULL , NULL , & si , & pi ) )
2014-06-21 23:55:24 +00:00
return GetLastError ( ) ;
WaitForSingleObject ( pi . hProcess , INFINITE ) ;
GetExitCodeProcess ( pi . hProcess , & si . cb ) ;
CloseHandle ( pi . hThread ) , CloseHandle ( pi . hProcess ) ;
return ( int ) si . cb ;
}
# endif //~ _UNICODE
# endif //~ _WIN32
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.
2013-12-08 14:34:38 +00:00
const TCHAR * const prefix = _T ( " IF 1==1 " ) ;
2013-05-04 13:32:47 +00:00
# ifdef _UNICODE
2013-12-08 14:34:38 +00:00
if ( ! command ) return 0 ; else if ( ! * command ) return 1 ;
2013-05-04 13:32:47 +00:00
tstring fixedcmd = _tgetenv ( _T ( " COMSPEC " ) ) ;
if ( ! fixedcmd . length ( ) ) fixedcmd = _T ( " CMD.EXE " ) ;
2013-12-08 14:34:38 +00:00
fixedcmd + = _T ( " /C " ) , fixedcmd + = prefix ;
2013-05-04 13:32:47 +00:00
return RunChildProcessRedirected ( fixedcmd . c_str ( ) , command ) ;
# else
2014-01-22 09:54:21 +00:00
tstring fixedcmd = prefix ;
fixedcmd + = _T ( " " ) , fixedcmd + = command ;
2013-05-04 13:32:47 +00:00
return _tsystem ( fixedcmd . c_str ( ) ) ;
2013-12-08 14:34:38 +00:00
# endif // ~_UNICODE
# else // !_WIN32
# ifndef _UNICODE
2014-01-21 14:13:00 +00:00
TCHAR * cmd = const_cast < TCHAR * > ( command ) ;
PATH_CONVERT ( cmd ) ;
return _tsystem ( cmd ) ;
2013-12-08 14:34:38 +00:00
# else
return NSISRT_wsystem ( command ) ;
2006-07-30 10:29:23 +00:00
# endif
2013-12-08 14:34:38 +00:00
# endif // ~_WIN32
2006-07-30 10:29:23 +00:00
}
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 ( ) ;
}
2016-11-23 15:42:20 +00:00
# endif //~ _WIN32
2013-05-04 13:32:47 +00:00
# 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 ;
2013-12-08 14:34:38 +00:00
return succ | | ( sizeof ( TCHAR ) > 1 & & WinStdIO_IsConsole ( osd ) ) ; // Don't care about BOM for WriteConsoleW
2013-05-04 13:32:47 +00:00
}
bool WINAPI WinStdIO_OStreamWrite ( WINSIO_OSDATA & osd , const wchar_t * Str , UINT cch )
{
2014-02-08 00:13:52 +00:00
if ( ( UINT ) - 1 = = cch ) cch = ( UINT ) _tcslen ( Str ) ;
2013-05-04 13:32:47 +00:00
DWORD cbio ;
if ( WinStdIO_IsConsole ( osd ) )
2019-08-16 19:07:02 +00:00
return WriteConsoleW ( osd . hNative , Str , cch , & cbio , 0 ) | | ! cch ;
2013-05-04 13:32:47 +00:00
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 ;
}
2016-11-22 21:17:00 +00:00
static WINSIO_OSDATA * WinStdIO_GetNativeStreamData ( FILE * strm )
{
extern WINSIO_OSDATA g_osdata_stdout , g_osdata_stderr ;
if ( g_output = = strm ) return & g_osdata_stdout ;
return g_errout = = strm ? & g_osdata_stderr : NULL ;
}
2013-05-04 13:32:47 +00:00
int WINAPI WinStdIO_vfwprintf ( FILE * strm , const wchar_t * Fmt , va_list val )
{
2016-11-22 21:17:00 +00:00
WINSIO_OSDATA * pOSD ;
if ( Fmt & & ( pOSD = WinStdIO_GetNativeStreamData ( strm ) ) )
2013-05-04 13:32:47 +00:00
{
ExpandoString < wchar_t , NSIS_MAX_STRLEN > buf ;
errno = ENOMEM ;
2017-04-25 13:09:41 +00:00
const size_t cchfmt = buf . StrVFmt ( Fmt , val , false ) ;
2014-02-08 00:13:52 +00:00
UINT cch = ( UINT ) cchfmt ;
assert ( sizeof ( size_t ) < = 4 | | cchfmt = = cch ) ;
2016-11-22 21:17:00 +00:00
if ( cch & & ! WinStdIO_OStreamWrite ( * pOSD , buf , cch ) )
2013-05-04 13:32:47 +00:00
{
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 ;
}
2016-11-23 15:42:20 +00:00
static HANDLE NSISRT_FastGetConsoleScreenHandle ( )
{
extern WINSIO_OSDATA g_osdata_stdout , g_osdata_stderr ;
return WinStdIO_IsConsole ( g_osdata_stdout ) ? g_osdata_stdout . hNative : g_osdata_stderr . hNative ;
}
bool NSISRT_Initialize ( ) // Init function for MakeNSIS Win32
{
static bool inited = false ;
if ( inited ) return inited ;
extern WINSIO_OSDATA g_osdata_stdout , g_osdata_stderr ;
g_osdata_stderr . mode = g_osdata_stdout . mode = 0 , g_osdata_stderr . hNative = g_osdata_stdout . hNative = 0 ;
return ( inited = true ) ;
}
# elif defined(_WIN32)
# define NSISRT_FastGetConsoleScreenHandle NSISRT_GetConsoleScreenHandle
bool NSISRT_Initialize ( ) { return true ; } // Init function for non-MakeNSIS Win32 (NSISRT_DEFINEGLOBALS sets g_output and g_errout)
2018-10-24 19:01:00 +00:00
static HANDLE NSISRT_GetConsoleScreenHandle ( )
{
DWORD cm ;
HANDLE hCon = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
return GetConsoleMode ( hCon , & cm ) ? hCon : GetStdHandle ( STD_ERROR_HANDLE ) ;
}
2013-05-04 13:32:47 +00:00
# endif
2010-03-24 17:22:56 +00:00
2016-11-22 23:11:33 +00:00
void PrintColorFmtErrMsg ( const TCHAR * fmtstr , va_list args )
{
PrintColorFmtMsg_WARN ( _T ( " " ) ) ; // flush g_output
SetPrintColorERR ( ) ;
_vftprintf ( g_errout , fmtstr , args ) , fflush ( g_errout ) ;
ResetPrintColor ( ) ;
}
2011-11-09 10:30:11 +00:00
void PrintColorFmtMsg ( unsigned int type , const TCHAR * fmtstr , va_list args )
{
# ifdef _WIN32
2016-11-23 15:42:20 +00:00
HANDLE hWin32Con = NSISRT_FastGetConsoleScreenHandle ( ) ;
2011-11-09 10:30:11 +00:00
static INT32 contxtattrbak = - 1 ;
WORD txtattr = 0 ;
if ( contxtattrbak < 0 )
{
if ( - 1 = = contxtattrbak )
{
CONSOLE_SCREEN_BUFFER_INFO csbi ;
contxtattrbak = - 2 ;
2013-12-08 14:34:38 +00:00
if ( GetConsoleScreenBufferInfo ( hWin32Con , & csbi ) )
2011-11-09 10:30:11 +00:00
{
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
}
2013-12-08 14:34:38 +00:00
unsigned char Platform_SupportsUTF8Conversion ( )
2011-12-05 23:44:26 +00:00
{
2013-12-08 14:34:38 +00:00
static unsigned char cached = 0 ;
if ( 0 = = cached ) cached = 1 + ! ! IsValidCodePage ( CP_UTF8 ) ;
return ( cached - 1 ) ;
}
void * operator new ( size_t size ) NSIS_CXX_THROWSPEC ( bad_alloc )
{
void * p = malloc ( size ) ;
if ( ! p ) throw bad_alloc ( ) ;
return p ;
}
void * operator new [ ] ( size_t size ) NSIS_CXX_THROWSPEC ( bad_alloc )
{
return operator new ( size ) ;
}
2018-06-02 00:38:45 +00:00
void operator delete ( void * p ) NSIS_CXX_NOEXCEPT ( ) { if ( p ) free ( p ) ; }
void operator delete [ ] ( void * p ) NSIS_CXX_NOEXCEPT ( ) { if ( p ) free ( p ) ; }