2010-11-06 23:04:47 +01:00
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
2017-03-12 12:12:49 +01:00
// Copyright (C) 2004-2017 LoRd_MuldeR <MuldeR2@GMX.de>
2010-11-06 23:04:47 +01:00
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
2013-10-23 20:56:57 +02:00
// (at your option) any later version, but always including the *additional*
// restrictions defined in the "License.txt" file.
2010-11-06 23:04:47 +01:00
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
# include "Thread_Initialization.h"
2014-11-25 02:14:42 +01:00
//Internal
2014-12-20 23:44:43 +01:00
# define LAMEXP_INC_TOOLS 1
2011-10-19 00:24:03 +02:00
# include "Tools.h"
2014-12-20 23:44:43 +01:00
# include "LockedFile.h"
2015-08-30 13:47:08 +02:00
# include "FileHash.h"
2013-10-29 02:05:43 +01:00
# include "Tool_Abstract.h"
2010-11-06 23:04:47 +01:00
2014-11-25 02:14:42 +01:00
//MUtils
# include <MUtils/Global.h>
2014-11-25 18:23:03 +01:00
# include <MUtils/OSSupport.h>
2014-12-20 23:44:43 +01:00
# include <MUtils/Translation.h>
2014-11-30 21:32:23 +01:00
# include <MUtils/Exception.h>
2014-11-25 02:14:42 +01:00
//Qt
2010-11-11 22:58:02 +01:00
# include <QFileInfo>
# include <QCoreApplication>
2010-11-12 15:58:53 +01:00
# include <QProcess>
2010-12-12 01:49:07 +01:00
# include <QMap>
# include <QDir>
2011-01-04 19:58:18 +01:00
# include <QResource>
2011-12-18 15:19:07 +01:00
# include <QTextStream>
2012-04-29 21:17:51 +02:00
# include <QRunnable>
# include <QThreadPool>
# include <QMutex>
2013-10-18 20:49:22 +02:00
# include <QQueue>
2014-12-06 15:54:58 +01:00
# include <QElapsedTimer>
2015-04-26 17:27:36 +02:00
# include <QVector>
2015-05-03 17:03:15 +02:00
2015-08-30 13:47:08 +02:00
/* enable custom tools? */
static const bool ENABLE_CUSTOM_TOOLS = true ;
2011-10-19 00:24:03 +02:00
/* helper macros */
2011-10-18 18:54:56 +02:00
# define PRINT_CPU_TYPE(X) case X: qDebug("Selected CPU is: " #X)
2015-05-03 17:03:15 +02:00
# define MAKE_REGEXP(STR) (((STR) && ((STR)[0])) ? QRegExp((STR)) : QRegExp())
2013-10-16 18:24:16 +02:00
/* constants */
2012-04-29 21:17:51 +02:00
static const double g_allowedExtractDelay = 12.0 ;
2013-10-16 18:24:16 +02:00
static const size_t BUFF_SIZE = 512 ;
2016-04-23 13:34:45 +02:00
static const size_t EXPECTED_TOOL_COUNT = 29 ;
2013-11-01 19:34:27 +01:00
2013-11-02 16:39:59 +01:00
/* number of CPU cores -> number of threads */
static unsigned int cores2threads ( const unsigned int cores )
{
static const size_t LUT_LEN = 4 ;
static const struct
{
const unsigned int upperBound ;
const double coeffs [ 4 ] ;
}
LUT [ LUT_LEN ] =
{
{ 4 , { - 0.052695810565 , 0.158087431694 , 4.982841530055 , - 1.088233151184 } } ,
{ 8 , { 0.042431693989 , - 0.983442622951 , 9.548961748634 , - 7.176393442623 } } ,
{ 12 , { - 0.006277322404 , 0.185573770492 , 0.196830601093 , 17.762622950820 } } ,
{ 32 , { 0.000673497268 , - 0.064655737705 , 3.199584699454 , 5.751606557377 } }
} ;
size_t index = 0 ;
while ( ( cores > LUT [ index ] . upperBound ) & & ( index < ( LUT_LEN - 1 ) ) ) index + + ;
const double x = qBound ( 1.0 , double ( cores ) , double ( LUT [ LUT_LEN - 1 ] . upperBound ) ) ;
const double y = ( LUT [ index ] . coeffs [ 0 ] * pow ( x , 3.0 ) ) + ( LUT [ index ] . coeffs [ 1 ] * pow ( x , 2.0 ) ) + ( LUT [ index ] . coeffs [ 2 ] * x ) + LUT [ index ] . coeffs [ 3 ] ;
return qRound ( abs ( y ) ) ;
}
2012-04-29 21:17:51 +02:00
////////////////////////////////////////////////////////////
2015-04-26 17:27:36 +02:00
// BaseTask class
2012-04-29 21:17:51 +02:00
////////////////////////////////////////////////////////////
2015-04-26 17:27:36 +02:00
class BaseTask : public QRunnable
2012-04-29 21:17:51 +02:00
{
public :
2015-04-26 17:27:36 +02:00
BaseTask ( void )
2012-04-29 21:17:51 +02:00
{
}
2015-04-26 17:27:36 +02:00
~ BaseTask ( void )
2013-10-18 20:49:22 +02:00
{
}
2015-04-26 17:27:36 +02:00
static void clearFlags ( QMutexLocker & lock = QMutexLocker ( & s_mutex ) )
2012-04-29 21:17:51 +02:00
{
2013-10-16 18:24:16 +02:00
s_bExcept = false ;
s_errMsg [ 0 ] = char ( 0 ) ;
2012-04-29 21:17:51 +02:00
}
2015-04-26 17:27:36 +02:00
static bool getExcept ( void )
{
bool ret ;
QMutexLocker lock ( & s_mutex ) ;
ret = s_bExcept ;
return ret ;
}
2013-10-16 03:31:14 +02:00
2013-10-16 18:24:16 +02:00
static bool getErrMsg ( char * buffer , const size_t buffSize )
2013-10-16 03:31:14 +02:00
{
2013-10-16 18:24:16 +02:00
QMutexLocker lock ( & s_mutex ) ;
if ( s_errMsg [ 0 ] )
{
strncpy_s ( buffer , BUFF_SIZE , s_errMsg , _TRUNCATE ) ;
return true ;
}
return false ;
2013-10-16 03:31:14 +02:00
}
2012-04-29 21:17:51 +02:00
protected :
2015-04-26 17:27:36 +02:00
virtual void taskMain ( void ) = 0 ;
2012-05-04 04:01:10 +02:00
void run ( void )
2012-04-29 21:17:51 +02:00
{
try
{
2015-04-26 17:27:36 +02:00
if ( ! getExcept ( ) ) taskMain ( ) ;
2012-04-29 21:17:51 +02:00
}
2013-10-18 21:37:40 +02:00
catch ( const std : : exception & e )
2013-10-18 20:49:22 +02:00
{
QMutexLocker lock ( & s_mutex ) ;
if ( ! s_bExcept )
{
s_bExcept = true ;
strncpy_s ( s_errMsg , BUFF_SIZE , e . what ( ) , _TRUNCATE ) ;
}
lock . unlock ( ) ;
2015-04-26 17:27:36 +02:00
qWarning ( " OptionalInitTask exception error: \n %s \n \n " , e . what ( ) ) ;
2013-10-18 20:49:22 +02:00
}
catch ( . . . )
2012-04-29 21:17:51 +02:00
{
2013-10-16 18:24:16 +02:00
QMutexLocker lock ( & s_mutex ) ;
if ( ! s_bExcept )
2012-05-03 23:11:16 +02:00
{
2013-10-16 18:24:16 +02:00
s_bExcept = true ;
2013-10-18 20:49:22 +02:00
strncpy_s ( s_errMsg , BUFF_SIZE , " Unknown exception error! " , _TRUNCATE ) ;
2012-05-03 23:11:16 +02:00
}
2013-10-18 20:49:22 +02:00
lock . unlock ( ) ;
2015-04-26 17:27:36 +02:00
qWarning ( " OptionalInitTask encountered an unknown exception! " ) ;
2012-04-29 21:17:51 +02:00
}
}
2015-04-26 17:27:36 +02:00
static volatile bool s_bExcept ;
static QMutex s_mutex ;
static char s_errMsg [ BUFF_SIZE ] ;
} ;
QMutex BaseTask : : s_mutex ;
char BaseTask : : s_errMsg [ BUFF_SIZE ] = { ' \0 ' } ;
volatile bool BaseTask : : s_bExcept = false ;
////////////////////////////////////////////////////////////
// ExtractorTask class
////////////////////////////////////////////////////////////
class ExtractorTask : public BaseTask
{
public :
ExtractorTask ( QResource * const toolResource , const QDir & appDir , const QString & toolName , const QByteArray & toolHash , const unsigned int toolVersion , const QString & toolTag )
:
m_appDir ( appDir ) ,
2015-08-31 22:53:19 +02:00
m_tempPath ( MUtils : : temp_folder ( ) ) ,
2015-04-26 17:27:36 +02:00
m_toolName ( toolName ) ,
m_toolHash ( toolHash ) ,
m_toolVersion ( toolVersion ) ,
m_toolTag ( toolTag ) ,
m_toolResource ( toolResource )
{
/* Nothing to do */
}
~ ExtractorTask ( void )
{
}
static bool getCustom ( void )
{
bool ret ;
QMutexLocker lock ( & s_mutex ) ;
ret = s_bCustom ;
return ret ;
}
static void clearFlags ( void )
{
QMutexLocker lock ( & s_mutex ) ;
s_bCustom = false ;
BaseTask : : clearFlags ( lock ) ;
}
protected :
void taskMain ( void )
2013-10-16 18:24:16 +02:00
{
2015-08-30 13:47:08 +02:00
QScopedPointer < LockedFile > lockedFile ;
2013-10-16 18:24:16 +02:00
unsigned int version = m_toolVersion ;
2015-08-30 13:47:08 +02:00
const QFileInfo toolFileInfo ( m_toolName ) ;
const QString toolShrtName = QString ( " %1.%2 " ) . arg ( toolFileInfo . baseName ( ) . toLower ( ) , toolFileInfo . suffix ( ) . toLower ( ) ) ;
2013-10-18 20:49:22 +02:00
2015-08-30 13:47:08 +02:00
//Try to load a "custom" tool first
if ( ENABLE_CUSTOM_TOOLS )
2013-10-16 18:24:16 +02:00
{
2015-08-30 13:47:08 +02:00
const QFileInfo customTool ( QString ( " %1/tools/%2/%3 " ) . arg ( m_appDir . canonicalPath ( ) , QString : : number ( lamexp_version_build ( ) ) , toolShrtName ) ) ;
if ( customTool . exists ( ) & & customTool . isFile ( ) )
{
qDebug ( " Setting up file: %s <- %s " , toolShrtName . toLatin1 ( ) . constData ( ) , m_appDir . relativeFilePath ( customTool . canonicalFilePath ( ) ) . toLatin1 ( ) . constData ( ) ) ;
try
{
lockedFile . reset ( new LockedFile ( customTool . canonicalFilePath ( ) ) ) ;
version = UINT_MAX ; s_bCustom = true ;
}
catch ( std : : runtime_error & )
{
lockedFile . reset ( ) ;
}
}
2013-10-16 18:24:16 +02:00
}
2015-08-30 13:47:08 +02:00
//Try to load the tool from the "cache" next
if ( lockedFile . isNull ( ) )
2013-10-16 18:24:16 +02:00
{
2015-08-30 13:47:08 +02:00
const QFileInfo chachedTool ( QString ( " %1/cache/%2 " ) . arg ( m_appDir . canonicalPath ( ) , toolFileInfo . fileName ( ) ) ) ;
if ( chachedTool . exists ( ) & & chachedTool . isFile ( ) )
{
qDebug ( " Validating file: %s <- %s " , toolShrtName . toLatin1 ( ) . constData ( ) , m_appDir . relativeFilePath ( chachedTool . canonicalFilePath ( ) ) . toLatin1 ( ) . constData ( ) ) ;
try
{
lockedFile . reset ( new LockedFile ( chachedTool . canonicalFilePath ( ) , m_toolHash ) ) ;
}
catch ( std : : runtime_error & )
{
lockedFile . reset ( ) ;
}
}
2013-10-16 18:24:16 +02:00
}
2015-08-30 13:47:08 +02:00
//If still not initialized, extract tool now!
if ( lockedFile . isNull ( ) )
2013-10-16 18:24:16 +02:00
{
2015-08-30 13:47:08 +02:00
qDebug ( " Extracting file: %s -> %s " , m_toolName . toLatin1 ( ) . constData ( ) , toolShrtName . toLatin1 ( ) . constData ( ) ) ;
2015-08-31 22:53:19 +02:00
lockedFile . reset ( new LockedFile ( m_toolResource . data ( ) , QString ( " %1/lxp_%2 " ) . arg ( m_tempPath , toolShrtName ) , m_toolHash ) ) ;
2013-10-16 18:24:16 +02:00
}
2015-08-30 13:47:08 +02:00
//Register tool
lamexp_tools_register ( toolShrtName , lockedFile . take ( ) , version , m_toolTag ) ;
2013-10-16 18:24:16 +02:00
}
2012-04-29 21:17:51 +02:00
private :
2015-08-31 22:53:19 +02:00
static volatile bool s_bCustom ;
2015-04-26 17:27:36 +02:00
QScopedPointer < QResource > m_toolResource ;
2015-08-31 22:53:19 +02:00
const QDir m_appDir ;
const QString m_tempPath ;
const QString m_toolName ;
const QByteArray m_toolHash ;
const unsigned int m_toolVersion ;
const QString m_toolTag ;
2012-04-29 21:17:51 +02:00
} ;
2013-10-16 18:24:16 +02:00
volatile bool ExtractorTask : : s_bCustom = false ;
2011-06-24 18:17:04 +02:00
2015-04-26 17:27:36 +02:00
////////////////////////////////////////////////////////////
2015-05-03 17:03:15 +02:00
// InitAacEncTask class
2015-04-26 17:27:36 +02:00
////////////////////////////////////////////////////////////
2015-05-03 17:03:15 +02:00
class InitAacEncTask : public BaseTask
2015-04-26 17:27:36 +02:00
{
public :
2015-05-03 17:03:15 +02:00
InitAacEncTask ( const aac_encoder_t * const encoder_info )
2015-04-26 17:27:36 +02:00
:
2015-05-03 17:03:15 +02:00
m_encoder_info ( encoder_info )
2015-04-26 17:27:36 +02:00
{
}
2015-05-03 17:03:15 +02:00
~ InitAacEncTask ( void )
2015-04-26 17:27:36 +02:00
{
}
protected :
void taskMain ( void )
{
2016-01-30 19:00:37 +01:00
initAacEncImpl ( m_encoder_info - > toolName , m_encoder_info - > fileNames , m_encoder_info - > checkArgs ? ( QStringList ( ) < < QString : : fromLatin1 ( m_encoder_info - > checkArgs ) ) : QStringList ( ) , m_encoder_info - > toolMinVersion , m_encoder_info - > verDigits , m_encoder_info - > verShift , m_encoder_info - > verStr , MAKE_REGEXP ( m_encoder_info - > regExpVer ) , MAKE_REGEXP ( m_encoder_info - > regExpSig ) ) ;
2015-04-26 17:27:36 +02:00
}
2016-01-30 19:00:37 +01:00
static void initAacEncImpl ( const char * const toolName , const char * const fileNames [ ] , const QStringList & checkArgs , const quint32 & toolMinVersion , const quint32 & verDigits , const quint32 & verShift , const char * const verStr , QRegExp & regExpVer , QRegExp & regExpSig = QRegExp ( ) ) ;
2015-05-03 17:03:15 +02:00
2015-04-26 17:27:36 +02:00
private :
2015-05-03 17:03:15 +02:00
const aac_encoder_t * const m_encoder_info ;
2015-04-26 17:27:36 +02:00
} ;
2010-11-06 23:04:47 +01:00
////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////
2014-11-25 03:15:03 +01:00
InitializationThread : : InitializationThread ( const MUtils : : CPUFetaures : : cpu_info_t & cpuFeatures )
:
m_bSuccess ( false ) ,
m_slowIndicator ( false )
2010-11-06 23:04:47 +01:00
{
2014-11-25 03:15:03 +01:00
memcpy ( & m_cpuFeatures , & cpuFeatures , sizeof ( MUtils : : CPUFetaures : : cpu_info_t ) ) ;
2010-11-06 23:04:47 +01:00
}
2010-11-12 15:58:53 +01:00
////////////////////////////////////////////////////////////
// Thread Main
////////////////////////////////////////////////////////////
2010-11-06 23:04:47 +01:00
2013-11-01 19:34:27 +01:00
void InitializationThread : : run ( void )
{
try
{
2014-12-21 17:13:50 +01:00
doInit ( ) ;
2013-11-01 19:34:27 +01:00
}
catch ( const std : : exception & error )
{
2014-11-30 21:32:23 +01:00
MUTILS_PRINT_ERROR ( " \n GURU MEDITATION !!! \n \n Exception error: \n %s \n " , error . what ( ) ) ;
2014-11-25 18:23:03 +01:00
MUtils : : OS : : fatal_exit ( L " Unhandeled C++ exception error, application will exit! " ) ;
2013-11-01 19:34:27 +01:00
}
catch ( . . . )
{
2014-11-30 21:32:23 +01:00
MUTILS_PRINT_ERROR ( " \n GURU MEDITATION !!! \n \n Unknown exception error! \n " ) ;
2014-11-25 18:23:03 +01:00
MUtils : : OS : : fatal_exit ( L " Unhandeled C++ exception error, application will exit! " ) ;
2013-11-01 19:34:27 +01:00
}
}
double InitializationThread : : doInit ( const size_t threadCount )
2010-11-06 23:04:47 +01:00
{
m_bSuccess = false ;
delay ( ) ;
2011-03-21 17:36:43 +01:00
2011-04-11 02:53:29 +02:00
//CPU type selection
2011-10-18 18:54:56 +02:00
unsigned int cpuSupport = 0 ;
2016-12-23 22:19:21 +01:00
const bool haveSSE2 = ( m_cpuFeatures . features & MUtils : : CPUFetaures : : FLAG_SSE ) & & ( m_cpuFeatures . features & MUtils : : CPUFetaures : : FLAG_SSE2 ) ;
if ( haveSSE2 & & ( m_cpuFeatures . vendor & MUtils : : CPUFetaures : : VENDOR_INTEL ) )
2011-10-18 18:54:56 +02:00
{
2016-02-20 15:59:45 +01:00
if ( m_cpuFeatures . features & MUtils : : CPUFetaures : : FLAG_AVX )
{
cpuSupport = m_cpuFeatures . x64 ? CPU_TYPE_X64_AVX : CPU_TYPE_X86_AVX ;
}
else
{
cpuSupport = m_cpuFeatures . x64 ? CPU_TYPE_X64_SSE : CPU_TYPE_X86_SSE ;
}
2011-10-18 18:54:56 +02:00
}
else
{
cpuSupport = m_cpuFeatures . x64 ? CPU_TYPE_X64_GEN : CPU_TYPE_X86_GEN ;
}
2012-04-05 13:40:52 +02:00
//Hack to disable x64 on Wine, as x64 binaries won't run under Wine (tested with Wine 1.4 under Ubuntu 12.04 x64)
if ( cpuSupport & CPU_TYPE_X64_ALL )
{
2014-11-29 01:25:18 +01:00
if ( MUtils : : OS : : running_on_wine ( ) )
2012-04-05 13:40:52 +02:00
{
qWarning ( " Running under Wine on a 64-Bit system. Going to disable all x64 support! \n " ) ;
cpuSupport = ( cpuSupport = = CPU_TYPE_X64_SSE ) ? CPU_TYPE_X86_SSE : CPU_TYPE_X86_GEN ;
}
}
2011-10-21 16:17:22 +02:00
2011-10-18 18:54:56 +02:00
//Print selected CPU type
switch ( cpuSupport )
{
PRINT_CPU_TYPE ( CPU_TYPE_X86_GEN ) ; break ;
PRINT_CPU_TYPE ( CPU_TYPE_X86_SSE ) ; break ;
2016-02-20 15:59:45 +01:00
PRINT_CPU_TYPE ( CPU_TYPE_X86_AVX ) ; break ;
2011-10-18 18:54:56 +02:00
PRINT_CPU_TYPE ( CPU_TYPE_X64_GEN ) ; break ;
PRINT_CPU_TYPE ( CPU_TYPE_X64_SSE ) ; break ;
2016-02-20 15:59:45 +01:00
PRINT_CPU_TYPE ( CPU_TYPE_X64_AVX ) ; break ;
2014-11-30 21:32:23 +01:00
default : MUTILS_THROW ( " CPU support undefined! " ) ;
2011-10-18 18:54:56 +02:00
}
2013-10-21 15:00:55 +02:00
//Allocate queues
2013-10-18 20:49:22 +02:00
QQueue < QString > queueToolName ;
QQueue < QString > queueChecksum ;
QQueue < QString > queueVersInfo ;
QQueue < unsigned int > queueVersions ;
QQueue < unsigned int > queueCpuTypes ;
2010-12-12 01:49:07 +01:00
2011-04-11 02:53:29 +02:00
//Init properties
2013-10-16 18:24:16 +02:00
for ( int i = 0 ; true ; i + + )
2010-11-06 23:04:47 +01:00
{
2013-10-16 18:24:16 +02:00
if ( ! ( g_lamexp_tools [ i ] . pcName | | g_lamexp_tools [ i ] . pcHash | | g_lamexp_tools [ i ] . uiVersion ) )
2010-12-18 15:15:17 +01:00
{
break ;
}
else if ( g_lamexp_tools [ i ] . pcName & & g_lamexp_tools [ i ] . pcHash & & g_lamexp_tools [ i ] . uiVersion )
2010-11-06 23:04:47 +01:00
{
2013-10-18 20:49:22 +02:00
queueToolName . enqueue ( QString : : fromLatin1 ( g_lamexp_tools [ i ] . pcName ) ) ;
queueChecksum . enqueue ( QString : : fromLatin1 ( g_lamexp_tools [ i ] . pcHash ) ) ;
queueVersInfo . enqueue ( QString : : fromLatin1 ( g_lamexp_tools [ i ] . pcVersTag ) ) ;
queueCpuTypes . enqueue ( g_lamexp_tools [ i ] . uiCpuType ) ;
queueVersions . enqueue ( g_lamexp_tools [ i ] . uiVersion ) ;
2010-11-06 23:04:47 +01:00
}
2010-12-18 15:15:17 +01:00
else
{
qFatal ( " Inconsistent checksum data detected. Take care! " ) ;
}
2010-12-12 01:49:07 +01:00
}
2010-11-06 23:04:47 +01:00
2011-04-17 20:38:49 +02:00
QDir appDir = QDir ( QCoreApplication : : applicationDirPath ( ) ) . canonicalPath ( ) ;
2015-04-26 17:27:36 +02:00
QScopedPointer < QThreadPool > pool ( new QThreadPool ( ) ) ;
2013-11-02 16:39:59 +01:00
pool - > setMaxThreadCount ( ( threadCount > 0 ) ? threadCount : qBound ( 2U , cores2threads ( m_cpuFeatures . count ) , EXPECTED_TOOL_COUNT ) ) ;
2012-04-29 21:17:51 +02:00
ExtractorTask : : clearFlags ( ) ;
2014-12-06 15:54:58 +01:00
//Start the timer
QElapsedTimer timeExtractStart ;
timeExtractStart . start ( ) ;
2011-04-17 20:38:49 +02:00
2010-12-12 01:49:07 +01:00
//Extract all files
2013-10-18 20:49:22 +02:00
while ( ! ( queueToolName . isEmpty ( ) | | queueChecksum . isEmpty ( ) | | queueVersInfo . isEmpty ( ) | | queueCpuTypes . isEmpty ( ) | | queueVersions . isEmpty ( ) ) )
2010-12-12 01:49:07 +01:00
{
2013-10-18 20:49:22 +02:00
const QString toolName = queueToolName . dequeue ( ) ;
const QString checksum = queueChecksum . dequeue ( ) ;
const QString versInfo = queueVersInfo . dequeue ( ) ;
const unsigned int cpuType = queueCpuTypes . dequeue ( ) ;
const unsigned int version = queueVersions . dequeue ( ) ;
2011-04-11 02:53:29 +02:00
2013-10-18 20:49:22 +02:00
const QByteArray toolHash ( checksum . toLatin1 ( ) ) ;
if ( toolHash . size ( ) ! = 96 )
{
2014-11-25 02:14:42 +01:00
qFatal ( " The checksum for \" %s \" has an invalid size! " , MUTILS_UTF8 ( toolName ) ) ;
2013-11-01 19:34:27 +01:00
return - 1.0 ;
2010-11-06 23:04:47 +01:00
}
2013-10-18 20:49:22 +02:00
2015-08-06 21:38:45 +02:00
QScopedPointer < QResource > resource ( new QResource ( QString ( " :/tools/%1 " ) . arg ( toolName ) ) ) ;
2013-10-18 20:49:22 +02:00
if ( ! ( resource - > isValid ( ) & & resource - > data ( ) ) )
2010-11-06 23:04:47 +01:00
{
2014-11-25 02:14:42 +01:00
qFatal ( " The resource for \" %s \" could not be found! " , MUTILS_UTF8 ( toolName ) ) ;
2013-11-01 19:34:27 +01:00
return - 1.0 ;
2010-11-06 23:04:47 +01:00
}
2013-10-18 20:49:22 +02:00
if ( cpuType & cpuSupport )
{
2015-08-07 01:57:28 +02:00
pool - > start ( new ExtractorTask ( resource . take ( ) , appDir , toolName , toolHash , version , versInfo ) ) ;
2013-10-18 20:49:22 +02:00
continue ;
}
}
//Sanity Check
if ( ! ( queueToolName . isEmpty ( ) & & queueChecksum . isEmpty ( ) & & queueVersInfo . isEmpty ( ) & & queueCpuTypes . isEmpty ( ) & & queueVersions . isEmpty ( ) ) )
{
qFatal ( " Checksum queues *not* empty fater verification completed. Take care! " ) ;
2010-11-06 23:04:47 +01:00
}
2012-05-03 23:11:16 +02:00
2012-04-29 21:17:51 +02:00
//Wait for extrator threads to finish
pool - > waitForDone ( ) ;
2014-12-06 15:54:58 +01:00
//Performance measure
2014-12-21 17:13:50 +01:00
const double delayExtract = double ( timeExtractStart . elapsed ( ) ) / 1000.0 ;
2014-12-06 15:54:58 +01:00
timeExtractStart . invalidate ( ) ;
2013-10-16 18:24:16 +02:00
2012-04-29 21:17:51 +02:00
//Make sure all files were extracted correctly
2013-10-16 18:24:16 +02:00
if ( ExtractorTask : : getExcept ( ) )
2012-04-29 21:17:51 +02:00
{
2013-10-16 18:24:16 +02:00
char errorMsg [ BUFF_SIZE ] ;
if ( ExtractorTask : : getErrMsg ( errorMsg , BUFF_SIZE ) )
{
qFatal ( " At least one of the required tools could not be initialized: \n %s " , errorMsg ) ;
2013-11-01 19:34:27 +01:00
return - 1.0 ;
2013-10-16 18:24:16 +02:00
}
qFatal ( " At least one of the required tools could not be initialized! " ) ;
2013-11-01 19:34:27 +01:00
return - 1.0 ;
2012-04-29 21:17:51 +02:00
}
2011-04-17 20:38:49 +02:00
qDebug ( " All extracted. \n " ) ;
//Using any custom tools?
2012-04-29 21:17:51 +02:00
if ( ExtractorTask : : getCustom ( ) )
2011-04-17 20:38:49 +02:00
{
qWarning ( " Warning: Using custom tools, you might encounter unexpected problems! \n " ) ;
}
2010-11-11 22:58:02 +01:00
2011-01-25 01:41:57 +01:00
//Check delay
2014-12-21 17:13:50 +01:00
if ( delayExtract > g_allowedExtractDelay )
2011-01-25 01:41:57 +01:00
{
2011-06-24 18:17:04 +02:00
m_slowIndicator = true ;
2011-01-25 01:41:57 +01:00
qWarning ( " Extracting tools took %.3f seconds -> probably slow realtime virus scanner. " , delayExtract ) ;
qWarning ( " Please report performance problems to your anti-virus developer !!! \n " ) ;
}
2013-06-29 18:06:21 +02:00
else
{
2014-12-21 17:13:50 +01:00
qDebug ( " Extracting the tools took %.3f seconds (OK). \n " , delayExtract ) ;
2013-06-29 18:06:21 +02:00
}
2011-01-25 01:41:57 +01:00
2011-01-04 19:58:18 +01:00
//Register all translations
initTranslations ( ) ;
2011-11-21 01:22:41 +01:00
//Look for AAC encoders
2015-05-03 17:03:15 +02:00
InitAacEncTask : : clearFlags ( ) ;
for ( size_t i = 0 ; g_lamexp_aacenc [ i ] . toolName ; i + + )
2015-04-26 17:27:36 +02:00
{
2015-05-03 17:03:15 +02:00
pool - > start ( new InitAacEncTask ( & ( g_lamexp_aacenc [ i ] ) ) ) ;
2015-04-26 17:27:36 +02:00
}
pool - > waitForDone ( ) ;
//Make sure initialization finished correctly
2015-05-03 17:03:15 +02:00
if ( InitAacEncTask : : getExcept ( ) )
2015-04-26 17:27:36 +02:00
{
char errorMsg [ BUFF_SIZE ] ;
2015-05-03 17:03:15 +02:00
if ( InitAacEncTask : : getErrMsg ( errorMsg , BUFF_SIZE ) )
2015-04-26 17:27:36 +02:00
{
qFatal ( " At least one optional component failed to initialize: \n %s " , errorMsg ) ;
return - 1.0 ;
}
qFatal ( " At least one optional component failed to initialize! " ) ;
return - 1.0 ;
}
2011-08-19 15:27:58 +02:00
2010-11-12 15:58:53 +01:00
m_bSuccess = true ;
2013-11-01 19:34:27 +01:00
delay ( ) ;
return delayExtract ;
}
2010-11-12 15:58:53 +01:00
////////////////////////////////////////////////////////////
2014-12-25 00:47:34 +01:00
// INTERNAL FUNCTIONS
2010-11-12 15:58:53 +01:00
////////////////////////////////////////////////////////////
void InitializationThread : : delay ( void )
{
2014-11-30 21:32:23 +01:00
MUtils : : OS : : sleep_ms ( 333 ) ;
2010-11-12 15:58:53 +01:00
}
2014-12-25 00:47:34 +01:00
////////////////////////////////////////////////////////////
// Translation Support
////////////////////////////////////////////////////////////
2011-01-04 19:58:18 +01:00
void InitializationThread : : initTranslations ( void )
{
//Search for language files
2014-12-20 23:44:43 +01:00
const QDir qmDirectory ( " :/localization " ) ;
const QStringList qmFiles = qmDirectory . entryList ( QStringList ( ) < < " LameXP_??.qm " , QDir : : Files , QDir : : Name ) ;
2011-01-04 19:58:18 +01:00
//Make sure we found at least one translation
if ( qmFiles . count ( ) < 1 )
{
qFatal ( " Could not find any translation files! " ) ;
return ;
}
2014-12-20 23:44:43 +01:00
//Initialize variables
const QString langResTemplate ( " :/localization/%1.txt " ) ;
QRegExp langIdExp ( " ^LameXP_( \\ w \\ w) \ \ . qm $ " , Qt::CaseInsensitive) ;
2011-01-04 19:58:18 +01:00
//Add all available translations
2014-12-20 23:44:43 +01:00
for ( QStringList : : ConstIterator iter = qmFiles . constBegin ( ) ; iter ! = qmFiles . constEnd ( ) ; iter + + )
2011-01-04 19:58:18 +01:00
{
2014-12-20 23:44:43 +01:00
const QString langFile = qmDirectory . absoluteFilePath ( * iter ) ;
2011-01-04 19:58:18 +01:00
QString langId , langName ;
2011-12-19 17:38:36 +01:00
unsigned int systemId = 0 , country = 0 ;
2011-01-04 19:58:18 +01:00
2014-12-20 23:44:43 +01:00
if ( QFileInfo ( langFile ) . isFile ( ) & & ( langIdExp . indexIn ( * iter ) > = 0 ) )
2011-01-04 19:58:18 +01:00
{
langId = langIdExp . cap ( 1 ) . toLower ( ) ;
2015-08-06 21:38:45 +02:00
QScopedPointer < QResource > langRes ( new QResource ( langResTemplate . arg ( * iter ) ) ) ;
if ( langRes - > isValid ( ) & & langRes - > size ( ) > 0 )
2011-12-18 15:19:07 +01:00
{
2015-08-06 21:38:45 +02:00
QByteArray data = QByteArray : : fromRawData ( reinterpret_cast < const char * > ( langRes - > data ( ) ) , langRes - > size ( ) ) ;
2011-12-18 15:19:07 +01:00
QTextStream stream ( & data , QIODevice : : ReadOnly ) ;
stream . setAutoDetectUnicode ( false ) ; stream . setCodec ( " UTF-8 " ) ;
2014-12-20 23:44:43 +01:00
while ( ! ( stream . atEnd ( ) | | ( stream . status ( ) ! = QTextStream : : Ok ) ) )
2011-12-18 15:19:07 +01:00
{
QStringList langInfo = stream . readLine ( ) . simplified ( ) . split ( " , " , QString : : SkipEmptyParts ) ;
2014-12-20 23:44:43 +01:00
if ( langInfo . count ( ) > = 3 )
2011-12-18 15:19:07 +01:00
{
systemId = langInfo . at ( 0 ) . trimmed ( ) . toUInt ( ) ;
2011-12-19 17:38:36 +01:00
country = langInfo . at ( 1 ) . trimmed ( ) . toUInt ( ) ;
2011-12-19 15:48:50 +01:00
langName = langInfo . at ( 2 ) . trimmed ( ) ;
2011-12-18 15:19:07 +01:00
break ;
}
}
}
2011-01-04 19:58:18 +01:00
}
2014-12-20 23:44:43 +01:00
if ( ! ( langId . isEmpty ( ) | | langName . isEmpty ( ) | | ( systemId = = 0 ) ) )
2011-01-04 19:58:18 +01:00
{
2014-12-20 23:44:43 +01:00
if ( MUtils : : Translation : : insert ( langId , langFile , langName , systemId , country ) )
2011-01-04 19:58:18 +01:00
{
2014-12-20 23:44:43 +01:00
qDebug ( " Registering translation: %s = %s (%u) [%u] " , MUTILS_UTF8 ( * iter ) , MUTILS_UTF8 ( langName ) , systemId , country ) ;
2011-12-18 15:19:07 +01:00
}
else
{
2014-12-20 23:44:43 +01:00
qWarning ( " Failed to register: %s " , langFile . toLatin1 ( ) . constData ( ) ) ;
2011-01-04 19:58:18 +01:00
}
}
}
qDebug ( " All registered. \n " ) ;
}
2014-12-25 00:47:34 +01:00
////////////////////////////////////////////////////////////
// AAC Encoder Detection
////////////////////////////////////////////////////////////
2016-01-30 19:00:37 +01:00
void InitAacEncTask : : initAacEncImpl ( const char * const toolName , const char * const fileNames [ ] , const QStringList & checkArgs , const quint32 & toolMinVersion , const quint32 & verDigits , const quint32 & verShift , const char * const verStr , QRegExp & regExpVer , QRegExp & regExpSig )
2010-11-12 15:58:53 +01:00
{
2015-04-26 17:27:36 +02:00
static const size_t MAX_FILES = 8 ;
2011-04-17 20:38:49 +02:00
const QString appPath = QDir ( QCoreApplication : : applicationDirPath ( ) ) . canonicalPath ( ) ;
2015-04-26 17:27:36 +02:00
QFileInfoList fileInfo ;
for ( size_t i = 0 ; fileNames [ i ] & & ( fileInfo . count ( ) < MAX_FILES ) ; i + + )
2014-12-25 00:47:34 +01:00
{
2015-04-26 17:27:36 +02:00
fileInfo . append ( QFileInfo ( QString ( " %1/%2 " ) . arg ( appPath , QString : : fromLatin1 ( fileNames [ i ] ) ) ) ) ;
}
2010-11-11 22:58:02 +01:00
2015-04-26 17:27:36 +02:00
for ( QFileInfoList : : ConstIterator iter = fileInfo . constBegin ( ) ; iter ! = fileInfo . constEnd ( ) ; iter + + )
2014-12-25 00:47:34 +01:00
{
2015-04-26 17:27:36 +02:00
if ( ! ( iter - > exists ( ) & & iter - > isFile ( ) ) )
2014-12-25 00:47:34 +01:00
{
2015-04-26 17:27:36 +02:00
qDebug ( " %s encoder binaries not found -> Encoding support will be disabled! \n " , toolName ) ;
return ;
2014-12-25 00:47:34 +01:00
}
2015-04-26 17:27:36 +02:00
if ( ( iter - > suffix ( ) . compare ( " exe " , Qt : : CaseInsensitive ) = = 0 ) & & ( ! MUtils : : OS : : is_executable_file ( iter - > canonicalFilePath ( ) ) ) )
2014-01-19 17:19:01 +01:00
{
2015-04-26 17:27:36 +02:00
qDebug ( " %s executable is invalid -> %s support will be disabled! \n " , MUTILS_UTF8 ( iter - > fileName ( ) ) , toolName ) ;
2014-01-19 17:19:01 +01:00
return ;
}
}
2015-04-26 17:27:36 +02:00
qDebug ( " Found %s encoder binary: \n %s \n " , toolName , MUTILS_UTF8 ( fileInfo . first ( ) . canonicalFilePath ( ) ) ) ;
2010-11-12 15:58:53 +01:00
2015-04-26 17:27:36 +02:00
//Lock the encoder binaries
QScopedPointer < LockedFile > binaries [ MAX_FILES ] ;
2010-11-12 15:58:53 +01:00
try
{
2015-04-26 17:27:36 +02:00
size_t index = 0 ;
for ( QFileInfoList : : ConstIterator iter = fileInfo . constBegin ( ) ; iter ! = fileInfo . constEnd ( ) ; iter + + )
2010-11-12 15:58:53 +01:00
{
2015-04-26 17:27:36 +02:00
binaries [ index + + ] . reset ( new LockedFile ( iter - > canonicalFilePath ( ) ) ) ;
2010-11-12 15:58:53 +01:00
}
}
catch ( . . . )
{
2015-04-26 17:27:36 +02:00
qWarning ( " Failed to get excluive lock to encoder binary -> %s support will be disabled! " , toolName ) ;
2010-11-12 15:58:53 +01:00
return ;
}
QProcess process ;
2015-04-26 17:27:36 +02:00
MUtils : : init_process ( process , fileInfo . first ( ) . absolutePath ( ) ) ;
2016-01-30 19:00:37 +01:00
process . start ( fileInfo . first ( ) . canonicalFilePath ( ) , checkArgs ) ;
2010-11-12 15:58:53 +01:00
if ( ! process . waitForStarted ( ) )
{
2015-04-26 17:27:36 +02:00
qWarning ( " %s process failed to create! " , toolName ) ;
2010-11-18 22:37:35 +01:00
qWarning ( " Error message: \" %s \" \n " , process . errorString ( ) . toLatin1 ( ) . constData ( ) ) ;
2010-11-12 15:58:53 +01:00
process . kill ( ) ;
process . waitForFinished ( - 1 ) ;
return ;
}
2015-04-26 17:27:36 +02:00
quint32 toolVersion = 0 ;
bool sigFound = regExpSig . isEmpty ( ) ? true : false ;
2010-11-12 15:58:53 +01:00
while ( process . state ( ) ! = QProcess : : NotRunning )
{
if ( ! process . waitForReadyRead ( ) )
2010-11-11 22:58:02 +01:00
{
2010-11-12 15:58:53 +01:00
if ( process . state ( ) = = QProcess : : Running )
{
2015-04-26 17:27:36 +02:00
qWarning ( " %s process time out -> killing! " , toolName ) ;
2010-11-12 15:58:53 +01:00
process . kill ( ) ;
process . waitForFinished ( - 1 ) ;
return ;
}
2010-11-11 22:58:02 +01:00
}
2010-11-18 22:37:35 +01:00
while ( process . canReadLine ( ) )
2010-11-11 22:58:02 +01:00
{
2010-11-18 22:37:35 +01:00
QString line = QString : : fromUtf8 ( process . readLine ( ) . constData ( ) ) . simplified ( ) ;
2015-04-26 17:27:36 +02:00
if ( ( ! sigFound ) & & regExpSig . lastIndexIn ( line ) > = 0 )
2014-12-25 00:47:34 +01:00
{
2015-04-26 17:27:36 +02:00
sigFound = true ;
2014-12-25 00:47:34 +01:00
continue ;
}
2015-04-26 17:27:36 +02:00
if ( sigFound & & ( regExpVer . lastIndexIn ( line ) > = 0 ) )
2010-11-12 15:58:53 +01:00
{
2015-04-26 17:27:36 +02:00
quint32 tmp [ 8 ] ;
if ( MUtils : : regexp_parse_uint32 ( regExpVer , tmp , qMin ( verDigits , 8U ) ) )
2010-11-12 15:58:53 +01:00
{
2015-04-26 17:27:36 +02:00
toolVersion = 0 ;
for ( quint32 i = 0 ; i < verDigits ; i + + )
{
2016-02-03 20:50:58 +01:00
toolVersion = ( verShift > 0 ) ? ( ( toolVersion * verShift ) + qBound ( 0U , tmp [ i ] , ( verShift - 1 ) ) ) : tmp [ i ] ;
2015-04-26 17:27:36 +02:00
}
2010-11-12 15:58:53 +01:00
}
}
2010-11-11 22:58:02 +01:00
}
}
2010-11-12 15:58:53 +01:00
2015-04-26 17:27:36 +02:00
if ( toolVersion < = 0 )
2010-11-11 22:58:02 +01:00
{
2015-04-26 17:27:36 +02:00
qWarning ( " %s version could not be determined -> Encoding support will be disabled! " , toolName ) ;
2010-11-12 15:58:53 +01:00
return ;
2010-11-11 22:58:02 +01:00
}
2015-04-26 17:27:36 +02:00
else if ( toolVersion < toolMinVersion )
2014-12-25 00:47:34 +01:00
{
2015-04-26 17:27:36 +02:00
qWarning ( " %s version is too much outdated (%s) -> Encoding support will be disabled! " , toolName , MUTILS_UTF8 ( lamexp_version2string ( verStr , toolVersion , " N/A " ) ) ) ;
qWarning ( " Minimum required %s version currently is: %s \n " , toolName , MUTILS_UTF8 ( lamexp_version2string ( verStr , toolMinVersion , " N/A " ) ) ) ;
2014-12-25 00:47:34 +01:00
return ;
}
2015-04-26 17:27:36 +02:00
qDebug ( " Enabled %s encoder %s. \n " , toolName , MUTILS_UTF8 ( lamexp_version2string ( verStr , toolVersion , " N/A " ) ) ) ;
2014-12-25 00:47:34 +01:00
2015-04-26 17:27:36 +02:00
size_t index = 0 ;
for ( QFileInfoList : : ConstIterator iter = fileInfo . constBegin ( ) ; iter ! = fileInfo . constEnd ( ) ; iter + + )
2010-11-12 15:58:53 +01:00
{
2015-04-26 17:27:36 +02:00
lamexp_tools_register ( iter - > fileName ( ) , binaries [ index + + ] . take ( ) , toolVersion ) ;
2010-11-12 15:58:53 +01:00
}
2010-11-06 23:04:47 +01:00
}
2014-12-25 00:47:34 +01:00
////////////////////////////////////////////////////////////
// Self-Test Function
////////////////////////////////////////////////////////////
2011-10-19 00:24:03 +02:00
void InitializationThread : : selfTest ( void )
{
2016-02-20 15:59:45 +01:00
const unsigned int cpu [ 7 ] = { CPU_TYPE_X86_GEN , CPU_TYPE_X86_SSE , CPU_TYPE_X86_AVX , CPU_TYPE_X64_GEN , CPU_TYPE_X64_SSE , CPU_TYPE_X64_AVX , 0 } ;
2011-10-19 00:24:03 +02:00
2016-02-20 15:59:45 +01:00
for ( size_t k = 0 ; cpu [ k ] ; k + + )
2011-10-19 00:24:03 +02:00
{
qDebug ( " [TEST] " ) ;
switch ( cpu [ k ] )
{
PRINT_CPU_TYPE ( CPU_TYPE_X86_GEN ) ; break ;
PRINT_CPU_TYPE ( CPU_TYPE_X86_SSE ) ; break ;
2016-02-20 15:59:45 +01:00
PRINT_CPU_TYPE ( CPU_TYPE_X86_AVX ) ; break ;
2011-10-19 00:24:03 +02:00
PRINT_CPU_TYPE ( CPU_TYPE_X64_GEN ) ; break ;
PRINT_CPU_TYPE ( CPU_TYPE_X64_SSE ) ; break ;
2016-02-20 15:59:45 +01:00
PRINT_CPU_TYPE ( CPU_TYPE_X64_AVX ) ; break ;
default :
MUTILS_THROW ( " CPU support undefined! " ) ;
2011-10-19 00:24:03 +02:00
}
2013-10-20 19:12:55 +02:00
unsigned int n = 0 ;
for ( int i = 0 ; true ; i + + )
2011-10-19 00:24:03 +02:00
{
2013-10-20 19:12:55 +02:00
if ( ! ( g_lamexp_tools [ i ] . pcName | | g_lamexp_tools [ i ] . pcHash | | g_lamexp_tools [ i ] . uiVersion ) )
2011-10-19 00:24:03 +02:00
{
break ;
}
2013-10-20 19:12:55 +02:00
else if ( g_lamexp_tools [ i ] . pcName & & g_lamexp_tools [ i ] . pcHash & & g_lamexp_tools [ i ] . uiVersion )
{
const QString toolName = QString : : fromLatin1 ( g_lamexp_tools [ i ] . pcName ) ;
const QByteArray expectedHash = QByteArray ( g_lamexp_tools [ i ] . pcHash ) ;
if ( g_lamexp_tools [ i ] . uiCpuType & cpu [ k ] )
{
2014-11-25 02:14:42 +01:00
qDebug ( " %02i -> %s " , + + n , MUTILS_UTF8 ( toolName ) ) ;
2013-10-20 19:12:55 +02:00
QFile resource ( QString ( " :/tools/%1 " ) . arg ( toolName ) ) ;
if ( ! resource . open ( QIODevice : : ReadOnly ) )
{
2014-11-25 02:14:42 +01:00
qFatal ( " The resource for \" %s \" could not be opened! " , MUTILS_UTF8 ( toolName ) ) ;
2013-10-20 19:12:55 +02:00
break ;
}
2015-08-30 13:47:08 +02:00
QByteArray hash = FileHash : : computeHash ( resource ) ;
2013-10-20 19:12:55 +02:00
if ( hash . isNull ( ) | | _stricmp ( hash . constData ( ) , expectedHash . constData ( ) ) )
{
2014-11-25 02:14:42 +01:00
qFatal ( " Hash check for tool \" %s \" has failed! " , MUTILS_UTF8 ( toolName ) ) ;
2013-10-20 19:12:55 +02:00
break ;
}
resource . close ( ) ;
}
}
else
2011-10-19 00:24:03 +02:00
{
2013-10-20 19:12:55 +02:00
qFatal ( " Inconsistent checksum data detected. Take care! " ) ;
2011-10-19 00:24:03 +02:00
}
}
2013-11-01 19:34:27 +01:00
if ( n ! = EXPECTED_TOOL_COUNT )
2011-10-19 00:24:03 +02:00
{
2016-02-20 15:59:45 +01:00
qFatal ( " Tool count mismatch for CPU type %u. Should be %u, but got %u !!! " , cpu [ k ] , EXPECTED_TOOL_COUNT , n ) ;
2011-10-19 00:24:03 +02:00
}
qDebug ( " Done. \n " ) ;
}
}
2010-12-12 13:44:11 +01:00
2010-11-06 23:04:47 +01:00
////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////
2013-11-01 19:34:27 +01:00
/*NONE*/