OSDN Git Service

Updated web-update tool, again.
[lamexp/LameXP.git] / src / Thread_Initialization.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2011 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
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.
9 //
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.
14 //
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.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "Thread_Initialization.h"
23
24 #include "Global.h"
25 #include "LockedFile.h"
26
27 #include <QFileInfo>
28 #include <QCoreApplication>
29 #include <QProcess>
30 #include <QMap>
31 #include <QDir>
32 #include <QLibrary>
33 #include <QResource>
34
35 #include <Windows.h>
36
37 ////////////////////////////////////////////////////////////
38 // TOOLS
39 ////////////////////////////////////////////////////////////
40
41 static const struct
42 {
43         char *pcHash;
44         char *pcName;
45         unsigned int uiVersion;
46 }
47 g_lamexp_tools[] =
48 {
49         {"3b41f85dde8d4a5a0f4cd5f461099d0db24610ba", "alac.exe", UINT_MAX},
50         {"fb74ac8b73ad8cba2c3b4e6e61f23401d630dc22", "elevator.exe", UINT_MAX},
51         {"3c647950bccfcc75d0746c0772e7115684be4dc5", "faad.exe", UINT_MAX},
52         {"d33cd86f04bd4067e244d2804466583c7b90a4e2", "flac.exe", 121},
53         {"9328a50e89b54ec065637496d9681a7e3eebf915", "gpgv.exe", 1411},
54         {"d837bf6ee4dab557d8b02d46c75a24e58980fffa", "gpgv.gpg", UINT_MAX},
55         {"143fc001a2f6c56fe1b9e6f8a2eb2b53b9e1e504", "lame.exe", 39910},
56         {"a4e929cfaa42fa2e61a3d0c6434c77a06d45aef3", "mac.exe", 406},
57         {"61d584ffaf428e9afb0ed9bd32706a954af492b0", "mediainfo_i386.exe", 739},
58         {"81fb728cbc6057906fa1b637738e6aefe5dccf54", "mediainfo_x64.exe", 739},
59         {"55c293a80475f7aeccf449ac9487a4626e5139cb", "mpcdec.exe", UINT_MAX},
60         {"8bbf4a3fffe2ff143eb5ba2cf82ca16d676e865d", "mpg123.exe", UINT_MAX},
61         {"8dd7138714c3bcb39f5a3213413addba13d06f1e", "oggdec.exe", UINT_MAX},
62         {"ecd15abe103184aca96e406f5f1c82c6fb2e665d", "oggenc2_i386.exe", 287},
63         {"ffe0fbd73352396dc3752ac9d484dbfc754a226d", "oggenc2_sse2.exe", 287},
64         {"a8c50872e544a55495a824426e9378984f2ae01d", "oggenc2_x64.exe", 287},
65         {"cd95369051f96b9ca3a997658771c5ea52bc874d", "selfdelete.exe", UINT_MAX},
66         {"ffeaa70bd6321185eafcb067ab2dc441650038bf", "shorten.exe", UINT_MAX},
67         {"2d08c3586f9cf99f2e4c89ac54eeb595f63aef61", "sox.exe", 1431},
68         {"346ce516281c97e92e1b8957ddeca52edcf2d056", "speexdec.exe", UINT_MAX},
69         {"8a74b767cfe88bf88c068fdae0de02d65589d25e", "takc.exe", UINT_MAX},
70         {"d6e0de1e7a2d9dee10d06ae0b6b4f93b63205920", "ttaenc.exe", 341},
71         {"8c842eef65248b46fa6cb9a9e5714f575672d999", "valdec.exe", 31},
72         {"8159f4e824b3e343ece95ba6dbb5e16da9c4866e", "volumax.exe", UINT_MAX},
73         {"62e2805d1b2eb2a4d86a5ca6e6ea58010d05d2a7", "wget.exe", UINT_MAX},
74         {"a7e8aad52213e339ad985829722f35eab62be182", "wupdate.exe", UINT_MAX},
75         {"b7d14b3540d24df13119a55d97623a61412de6e3", "wvunpack.exe", 4601},
76         {NULL, NULL, NULL}
77 };
78
79 ////////////////////////////////////////////////////////////
80 // Constructor
81 ////////////////////////////////////////////////////////////
82
83 InitializationThread::InitializationThread(void)
84 {
85         m_bSuccess = false;
86 }
87
88 ////////////////////////////////////////////////////////////
89 // Thread Main
90 ////////////////////////////////////////////////////////////
91
92 void InitializationThread::run()
93 {
94         m_bSuccess = false;
95         delay();
96         
97         QMap<QString, QString> checksum;
98         QMap<QString, unsigned int> version;
99
100         //Init checksums
101         for(int i = 0; i < INT_MAX; i++)
102         {
103                 if(!g_lamexp_tools[i].pcName && !g_lamexp_tools[i].pcHash && !g_lamexp_tools[i].uiVersion)
104                 {
105                         break;
106                 }
107                 else if(g_lamexp_tools[i].pcName && g_lamexp_tools[i].pcHash && g_lamexp_tools[i].uiVersion)
108                 {
109                         const QString currentTool = QString::fromLatin1(g_lamexp_tools[i].pcName);
110                         checksum.insert(currentTool, QString::fromLatin1(g_lamexp_tools[i].pcHash));
111                         version.insert(currentTool, g_lamexp_tools[i].uiVersion);
112                 }
113                 else
114                 {
115                         qFatal("Inconsistent checksum data detected. Take care!");
116                 }
117         }
118
119         QDir toolsDir(":/tools/");
120         QList<QFileInfo> toolsList = toolsDir.entryInfoList(QStringList("*.*"), QDir::Files, QDir::Name);
121
122         //Extract all files
123         for(int i = 0; i < toolsList.count(); i++)
124         {
125                 try
126                 {
127                         QString toolName = toolsList.at(i).fileName().toLower();
128                         qDebug("Extracting file: %s", toolName.toLatin1().constData());
129                         QByteArray toolHash = checksum.take(toolName).toLatin1();
130                         unsigned int toolVersion = version.take(toolName);
131                         if(toolHash.size() != 40)
132                         {
133                                 throw "The required checksum is missing, take care!";
134                         }
135                         LockedFile *lockedFile = new LockedFile(QString(":/tools/%1").arg(toolName), QString(lamexp_temp_folder()).append(QString("/tool_%1").arg(toolName)), toolHash);
136                         lamexp_register_tool(toolName, lockedFile, toolVersion);
137                 }
138                 catch(char *errorMsg)
139                 {
140                         qFatal("At least one required tool could not be extracted:\n%s", errorMsg);
141                         return;
142                 }
143         }
144         
145         if(!checksum.isEmpty())
146         {
147                 qFatal("At least one required tool could not be found:\n%s", toolsDir.filePath(checksum.keys().first()).toLatin1().constData());
148                 return;
149         }
150         
151         qDebug("All extracted.\n");
152
153         //Register all translations
154         initTranslations();
155
156         //Look for Nero encoder
157         initNeroAac();
158         
159         //Look for WMA File decoder
160         initWmaDec();
161
162         delay();
163         m_bSuccess = true;
164 }
165
166 ////////////////////////////////////////////////////////////
167 // PUBLIC FUNCTIONS
168 ////////////////////////////////////////////////////////////
169
170 void InitializationThread::delay(void)
171 {
172         const char *temp = "|/-\\";
173         printf("Thread is doing something important... ?\b", temp[4]);
174
175         for(int i = 0; i < 20; i++)
176         {
177                 printf("%c\b", temp[i%4]);
178                 msleep(100);
179         }
180
181         printf("Done\n\n");
182 }
183
184 void InitializationThread::initTranslations(void)
185 {
186         //Search for language files
187         QStringList qmFiles = QDir(":/localization").entryList(QStringList() << "LameXP_??.qm", QDir::Files, QDir::Name);
188
189         //Make sure we found at least one translation
190         if(qmFiles.count() < 1)
191         {
192                 qFatal("Could not find any translation files!");
193                 return;
194         }
195
196         //Add all available translations
197         while(!qmFiles.isEmpty())
198         {
199                 QString langId, langName;
200                 unsigned int systemId = 0;
201                 QString qmFile = qmFiles.takeFirst();
202                 
203                 QRegExp langIdExp("LameXP_(\\w\\w)\\.qm", Qt::CaseInsensitive);
204                 if(langIdExp.indexIn(qmFile) >= 0)
205                 {
206                         langId = langIdExp.cap(1).toLower();
207                 }
208
209                 QResource langRes = (QString(":/localization/%1.txt").arg(qmFile));
210                 if(langRes.isValid() && langRes.size() > 0)
211                 {
212                         QStringList langInfo = QString::fromUtf8(reinterpret_cast<const char*>(langRes.data()), langRes.size()).simplified().split(",", QString::SkipEmptyParts);
213                         if(langInfo.count() == 2)
214                         {
215                                 systemId = langInfo.at(0).toUInt();
216                                 langName = langInfo.at(1);
217                         }
218                 }
219                 
220                 if(lamexp_translation_register(langId, qmFile, langName, systemId))
221                 {
222                         qDebug("Registering translation: %s = %s (%u)", qmFile.toLatin1().constData(), langName.toLatin1().constData(), systemId);
223                 }
224                 else
225                 {
226                         qWarning("Failed to register: %s", qmFile.toLatin1().constData());
227                 }
228         }
229
230         qDebug("All registered.\n");
231 }
232
233 void InitializationThread::initNeroAac(void)
234 {
235         QFileInfo neroFileInfo[3];
236         neroFileInfo[0] = QFileInfo(QString("%1/neroAacEnc.exe").arg(QCoreApplication::applicationDirPath()));
237         neroFileInfo[1] = QFileInfo(QString("%1/neroAacDec.exe").arg(QCoreApplication::applicationDirPath()));
238         neroFileInfo[2] = QFileInfo(QString("%1/neroAacTag.exe").arg(QCoreApplication::applicationDirPath()));
239         
240         bool neroFilesFound = true;
241         for(int i = 0; i < 3; i++)      { if(!neroFileInfo[i].exists()) neroFilesFound = false; }
242
243         //Lock the Nero binaries
244         if(!neroFilesFound)
245         {
246                 qDebug("Nero encoder binaries not found -> AAC encoding support will be disabled!\n");
247                 return;
248         }
249
250         qDebug("Found Nero AAC encoder binary:\n%s\n", neroFileInfo[0].canonicalFilePath().toUtf8().constData());
251
252         LockedFile *neroBin[3];
253         for(int i = 0; i < 3; i++) neroBin[i] = NULL;
254
255         try
256         {
257                 for(int i = 0; i < 3; i++)
258                 {
259                         neroBin[i] = new LockedFile(neroFileInfo[i].canonicalFilePath());
260                 }
261         }
262         catch(...)
263         {
264                 for(int i = 0; i < 3; i++) LAMEXP_DELETE(neroBin[i]);
265                 qWarning("Failed to get excluive lock to Nero encoder binary -> AAC encoding support will be disabled!");
266                 return;
267         }
268
269         QProcess process;
270         process.setProcessChannelMode(QProcess::MergedChannels);
271         process.setReadChannel(QProcess::StandardOutput);
272         process.start(neroFileInfo[0].canonicalFilePath(), QStringList() << "-help");
273
274         if(!process.waitForStarted())
275         {
276                 qWarning("Nero process failed to create!");
277                 qWarning("Error message: \"%s\"\n", process.errorString().toLatin1().constData());
278                 process.kill();
279                 process.waitForFinished(-1);
280                 for(int i = 0; i < 3; i++) LAMEXP_DELETE(neroBin[i]);
281                 return;
282         }
283
284         unsigned int neroVersion = 0;
285
286         while(process.state() != QProcess::NotRunning)
287         {
288                 if(!process.waitForReadyRead())
289                 {
290                         if(process.state() == QProcess::Running)
291                         {
292                                 qWarning("Nero process time out -> killing!");
293                                 process.kill();
294                                 process.waitForFinished(-1);
295                                 for(int i = 0; i < 3; i++) LAMEXP_DELETE(neroBin[i]);
296                                 return;
297                         }
298                 }
299
300                 while(process.canReadLine())
301                 {
302                         QString line = QString::fromUtf8(process.readLine().constData()).simplified();
303                         QStringList tokens = line.split(" ", QString::SkipEmptyParts, Qt::CaseInsensitive);
304                         int index1 = tokens.indexOf("Package");
305                         int index2 = tokens.indexOf("version:");
306                         if(index1 >= 0 && index2 >= 0 && index1 + 1 == index2 && index2 < tokens.count() - 1)
307                         {
308                                 QStringList versionTokens = tokens.at(index2 + 1).split(".", QString::SkipEmptyParts, Qt::CaseInsensitive);
309                                 if(versionTokens.count() == 4)
310                                 {
311                                         neroVersion = 0;
312                                         neroVersion += min(9, max(0, versionTokens.at(3).toInt()));
313                                         neroVersion += min(9, max(0, versionTokens.at(2).toInt())) * 10;
314                                         neroVersion += min(9, max(0, versionTokens.at(1).toInt())) * 100;
315                                         neroVersion += min(9, max(0, versionTokens.at(0).toInt())) * 1000;
316                                 }
317                         }
318                 }
319         }
320
321         if(!(neroVersion > 0))
322         {
323                 qWarning("Nero AAC version could not be determined -> AAC encoding support will be disabled!");
324                 for(int i = 0; i < 3; i++) LAMEXP_DELETE(neroBin[i]);
325                 return;
326         }
327         
328         for(int i = 0; i < 3; i++)
329         {
330                 lamexp_register_tool(neroFileInfo[i].fileName(), neroBin[i], neroVersion);
331         }
332 }
333
334
335 void InitializationThread::initWmaDec(void)
336 {
337         static const char* wmaDecoderComponentPath = "NCH Software/Components/wmawav/wmawav.exe";
338
339         LockedFile *wmaFileBin = NULL;
340         QFileInfo wmaFileInfo = QFileInfo(QString("%1/%2").arg(lamexp_known_folder(lamexp_folder_programfiles), wmaDecoderComponentPath));
341
342         if(!wmaFileInfo.exists())
343         {
344                 qDebug("WMA File Decoder not found -> WMA decoding support will be disabled!\n");
345                 return;
346         }
347
348         try
349         {
350                 wmaFileBin = new LockedFile(wmaFileInfo.canonicalFilePath());
351         }
352         catch(...)
353         {
354                 qWarning("Failed to get excluive lock to WMA File Decoder binary -> WMA decoding support will be disabled!");
355                 return;
356         }
357
358         QProcess process;
359         process.setProcessChannelMode(QProcess::MergedChannels);
360         process.setReadChannel(QProcess::StandardOutput);
361         process.start(wmaFileInfo.canonicalFilePath(), QStringList());
362
363         if(!process.waitForStarted())
364         {
365                 qWarning("WmaWav process failed to create!");
366                 qWarning("Error message: \"%s\"\n", process.errorString().toLatin1().constData());
367                 process.kill();
368                 process.waitForFinished(-1);
369                 return;
370         }
371
372         bool b_wmaWavFound = false;
373
374         while(process.state() != QProcess::NotRunning)
375         {
376                 if(!process.waitForReadyRead())
377                 {
378                         if(process.state() == QProcess::Running)
379                         {
380                                 qWarning("WmaWav process time out -> killing!");
381                                 process.kill();
382                                 process.waitForFinished(-1);
383                                 return;
384                         }
385                 }
386                 while(process.canReadLine())
387                 {
388                         QString line = QString::fromUtf8(process.readLine().constData()).simplified();
389                         if(line.contains("Usage: wmatowav.exe WMAFileSpec WAVFileSpec", Qt::CaseInsensitive))
390                         {
391                                 b_wmaWavFound = true;
392                         }
393                 }
394         }
395
396         if(!b_wmaWavFound)
397         {
398                 qWarning("WmaWav could not be identified -> WMA decoding support will be disabled!\n");
399                 LAMEXP_DELETE(wmaFileBin);
400                 return;
401         }
402
403         qDebug("Found WMA File Decoder binary:\n%s\n", wmaFileInfo.canonicalFilePath().toUtf8().constData());
404
405         if(wmaFileBin)
406         {
407                 lamexp_register_tool(wmaFileInfo.fileName(), wmaFileBin);
408         }
409 }
410
411 ////////////////////////////////////////////////////////////
412 // EVENTS
413 ////////////////////////////////////////////////////////////
414
415 /*NONE*/