1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2016 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "tool_abstract.h"
26 #include "model_options.h"
27 #include "model_preferences.h"
28 #include "model_sysinfo.h"
29 #include "job_object.h"
32 #include <MUtils/OSSupport.h>
36 #include <QMutexLocker>
38 #include <QCryptographicHash>
40 QMutex
AbstractTool::s_mutexStartProcess
;
42 // ------------------------------------------------------------
44 // ------------------------------------------------------------
46 static void APPEND_AND_CLEAR(QStringList
&list
, QString
&str
)
50 const QString temp
= str
.trimmed();
59 // ------------------------------------------------------------
60 // Constructor & Destructor
61 // ------------------------------------------------------------
63 AbstractTool::AbstractTool(JobObject
*jobObject
, const OptionsModel
*options
, const SysinfoModel
*const sysinfo
, const PreferencesModel
*const preferences
, JobStatus
&jobStatus
, volatile bool *abort
, volatile bool *pause
, QSemaphore
*semaphorePause
)
65 m_jobObject(jobObject
),
68 m_preferences(preferences
),
69 m_jobStatus(jobStatus
),
72 m_semaphorePause(semaphorePause
)
74 /*nothing to do here*/
77 // ------------------------------------------------------------
79 // ------------------------------------------------------------
81 unsigned int AbstractTool::checkVersion(bool &modified
)
83 if(m_preferences
->getSkipVersionTest())
85 log("Warning: Skipping the version check this time!");
86 return makeRevision(0xFFF0, 0xFFF0);
90 QList
<QRegExp
*> patterns
;
93 //Init encoder-specific values
94 checkVersion_init(patterns
, cmdLine
);
96 log("Creating process:");
97 if(!startProcess(process
, getBinaryPath(), cmdLine
, true, getExtraPath()))
102 bool bTimeout
= false;
103 bool bAborted
= false;
105 unsigned int revision
= UINT_MAX
;
106 unsigned int coreVers
= UINT_MAX
;
109 while(process
.state() != QProcess::NotRunning
)
117 if(!process
.waitForReadyRead())
119 if(process
.state() == QProcess::Running
)
122 qWarning("process timed out <-- killing!");
123 log("\nPROCESS TIMEOUT !!!");
128 PROCESS_PENDING_LINES(process
, checkVersion_parseLine
, patterns
, coreVers
, revision
, modified
);
131 if(!(bTimeout
|| bAborted
))
133 PROCESS_PENDING_LINES(process
, checkVersion_parseLine
, patterns
, coreVers
, revision
, modified
);
136 process
.waitForFinished();
137 if(process
.state() != QProcess::NotRunning
)
140 process
.waitForFinished(-1);
143 while(!patterns
.isEmpty())
145 QRegExp
*pattern
= patterns
.takeFirst();
146 MUTILS_DELETE(pattern
);
149 if(bTimeout
|| bAborted
|| (!checkVersion_succeeded(process
.exitCode())))
151 if(!(bTimeout
|| bAborted
))
153 log(tr("\nPROCESS EXITED WITH ERROR CODE: %1").arg(QString::number(process
.exitCode())));
158 if((revision
== UINT_MAX
) || (coreVers
== UINT_MAX
))
160 log(tr("\nFAILED TO DETERMINE VERSION INFO !!!"));
164 return makeRevision(coreVers
, revision
);
167 bool AbstractTool::checkVersion_succeeded(const int &exitCode
)
169 return (exitCode
== EXIT_SUCCESS
);
172 // ------------------------------------------------------------
174 // ------------------------------------------------------------
176 bool AbstractTool::startProcess(QProcess
&process
, const QString
&program
, const QStringList
&args
, bool mergeChannels
, const QString
&extraPath
)
178 QMutexLocker
lock(&s_mutexStartProcess
);
179 log(commandline2string(program
, args
) + "\n");
180 log("EXTRAPATH: '" + extraPath
+ "'\n");
182 MUtils::init_process(process
, QDir::tempPath(), true, extraPath
);
185 process
.setProcessChannelMode(QProcess::SeparateChannels
);
186 process
.setReadChannel(QProcess::StandardError
);
189 process
.start(program
, args
);
191 if(process
.waitForStarted())
193 m_jobObject
->addProcessToJob(&process
);
194 MUtils::OS::change_process_priority(&process
, m_preferences
->getProcessPriority());
199 log("Process creation has failed :-(");
200 QString errorMsg
= process
.errorString().trimmed();
201 if(!errorMsg
.isEmpty()) log(errorMsg
);
204 process
.waitForFinished(-1);
208 // ------------------------------------------------------------
210 // ------------------------------------------------------------
212 QString
AbstractTool::commandline2string(const QString
&program
, const QStringList
&arguments
)
214 const QString nativeProgfram
= QDir::toNativeSeparators(program
);
215 QString commandline
= (nativeProgfram
.contains(' ') ? QString("\"%1\"").arg(nativeProgfram
) : nativeProgfram
);
217 for(int i
= 0; i
< arguments
.count(); i
++)
219 commandline
+= (arguments
.at(i
).contains(' ') ? QString(" \"%1\"").arg(arguments
.at(i
)) : QString(" %1").arg(arguments
.at(i
)));
225 QStringList
AbstractTool::splitParams(const QString
¶ms
, const QString
&sourceFile
, const QString
&outputFile
)
228 bool ignoreWhitespaces
= false;
231 for(int i
= 0; i
< params
.length(); i
++)
233 const QChar c
= params
.at(i
);
234 if(c
== QLatin1Char('"'))
236 ignoreWhitespaces
= (!ignoreWhitespaces
);
239 else if((!ignoreWhitespaces
) && (c
== QChar::fromLatin1(' ')))
241 APPEND_AND_CLEAR(list
, temp
);
247 APPEND_AND_CLEAR(list
, temp
);
249 if(!sourceFile
.isEmpty())
251 list
.replaceInStrings("$(INPUT)", QDir::toNativeSeparators(sourceFile
), Qt::CaseInsensitive
);
254 if(!outputFile
.isEmpty())
256 list
.replaceInStrings("$(OUTPUT)", QDir::toNativeSeparators(outputFile
), Qt::CaseInsensitive
);
262 QString
AbstractTool::stringToHash(const QString
&string
)
264 QByteArray
result(10, char(0));
265 const QByteArray hash
= QCryptographicHash::hash(string
.toUtf8(), QCryptographicHash::Sha1
);
267 if((hash
.size() == 20) && (result
.size() == 10))
269 unsigned char *out
= reinterpret_cast<unsigned char*>(result
.data());
270 const unsigned char *in
= reinterpret_cast<const unsigned char*>(hash
.constData());
271 for(int i
= 0; i
< 10; i
++)
273 out
[i
] = (in
[i
] ^ in
[10+i
]);
277 return QString::fromLatin1(result
.toHex().constData());
280 unsigned int AbstractTool::makeRevision(const unsigned int &core
, const unsigned int &build
)
282 return ((core
& 0x0000FFFF) << 16) | (build
& 0x0000FFFF);
285 void AbstractTool::splitRevision(const unsigned int &revision
, unsigned int &core
, unsigned int &build
)
287 core
= (revision
& 0xFFFF0000) >> 16;
288 build
= (revision
& 0x0000FFFF);