OSDN Git Service

Refactored the "LockedFile" class + moved hash computation to a separate class, for...
authorLoRd_MuldeR <mulder2@gmx.de>
Sun, 30 Aug 2015 11:47:08 +0000 (13:47 +0200)
committerLoRd_MuldeR <mulder2@gmx.de>
Sun, 30 Aug 2015 11:47:08 +0000 (13:47 +0200)
15 files changed:
LameXP_VS2013.vcxproj
LameXP_VS2013.vcxproj.filters
LameXP_VS2015.vcxproj
LameXP_VS2015.vcxproj.filters
doc/Changelog.html
doc/Changelog.md
etc/NSIS/setup.nsi
src/Config.h
src/Dialog_About.cpp
src/FileHash.cpp [new file with mode: 0644]
src/FileHash.h [new file with mode: 0644]
src/Global_Tools.cpp
src/LockedFile.cpp
src/LockedFile.h
src/Thread_Initialization.cpp

index 3735619..a78e162 100644 (file)
@@ -314,6 +314,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
     <ClCompile Include="src\Encoder_Opus.cpp" />
     <ClCompile Include="src\Encoder_Vorbis.cpp" />
     <ClCompile Include="src\Encoder_Wave.cpp" />
+    <ClCompile Include="src\FileHash.cpp" />
     <ClCompile Include="src\Filter_Abstract.cpp" />
     <ClCompile Include="src\Filter_Downmix.cpp" />
     <ClCompile Include="src\Filter_Normalize.cpp" />
@@ -427,6 +428,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
     </CustomBuild>
+    <ClInclude Include="src\FileHash.h" />
     <ClInclude Include="src\IPCCommands.h" />
     <CustomBuild Include="src\Model_FileExts.h">
       <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" "%(FullPath)"</Command>
index c175cdb..83259fb 100644 (file)
     <ClCompile Include="tmp\LameXP\MOC_Model_FileExts.cpp">
       <Filter>Generated Files\MOC</Filter>
     </ClCompile>
+    <ClCompile Include="src\FileHash.cpp">
+      <Filter>Source Files\Misc</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Config.h">
     <ClInclude Include="src\MimeTypes.h">
       <Filter>Header Files\Misc</Filter>
     </ClInclude>
+    <ClInclude Include="src\FileHash.h">
+      <Filter>Header Files\Misc</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="gui\DropBox.ui">
index cbe358f..78f564c 100644 (file)
@@ -314,6 +314,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
     <ClCompile Include="src\Encoder_Opus.cpp" />
     <ClCompile Include="src\Encoder_Vorbis.cpp" />
     <ClCompile Include="src\Encoder_Wave.cpp" />
+    <ClCompile Include="src\FileHash.cpp" />
     <ClCompile Include="src\Filter_Abstract.cpp" />
     <ClCompile Include="src\Filter_Downmix.cpp" />
     <ClCompile Include="src\Filter_Normalize.cpp" />
@@ -427,6 +428,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
     </CustomBuild>
+    <ClInclude Include="src\FileHash.h" />
     <ClInclude Include="src\IPCCommands.h" />
     <CustomBuild Include="src\Model_FileExts.h">
       <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" "%(FullPath)"</Command>
index c175cdb..83259fb 100644 (file)
     <ClCompile Include="tmp\LameXP\MOC_Model_FileExts.cpp">
       <Filter>Generated Files\MOC</Filter>
     </ClCompile>
+    <ClCompile Include="src\FileHash.cpp">
+      <Filter>Source Files\Misc</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Config.h">
     <ClInclude Include="src\MimeTypes.h">
       <Filter>Header Files\Misc</Filter>
     </ClInclude>
+    <ClInclude Include="src\FileHash.h">
+      <Filter>Header Files\Misc</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="gui\DropBox.ui">
index e08b662..48c5422 100644 (file)
 <ul>
 <li>Upgraded build environment to Microsoft Visual Studio 2013 with Update-5<br /></li>
 <li>Updated Qt runtime libraries to v4.8.7 Final (2015-05-25), compiled with MSVC 12.0<br /></li>
-<li>Added Hungarian translation, contributed by Zityi's Translator Team <script type="text/javascript">
+<li>Added Hungarian translation, contributed by Zityi's Translator Team &lt;<script type="text/javascript">
 <!--
 h='&#x67;&#x6d;&#x61;&#x69;&#108;&#46;&#x63;&#x6f;&#x6d;';a='&#64;';n='&#122;&#x69;&#116;&#x79;&#x69;&#x73;&#x6f;&#102;&#116;';e=n+a+h;
 document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'">'+e+'<\/'+'a'+'>');
 // -->
-</script><noscript>&#122;&#x69;&#116;&#x79;&#x69;&#x73;&#x6f;&#102;&#116;&#32;&#x61;&#116;&#32;&#x67;&#x6d;&#x61;&#x69;&#108;&#32;&#100;&#x6f;&#116;&#32;&#x63;&#x6f;&#x6d;</noscript><br /></li>
+</script><noscript>&#122;&#x69;&#116;&#x79;&#x69;&#x73;&#x6f;&#102;&#116;&#32;&#x61;&#116;&#32;&#x67;&#x6d;&#x61;&#x69;&#108;&#32;&#100;&#x6f;&#116;&#32;&#x63;&#x6f;&#x6d;</noscript>&gt;<br /></li>
 <li>Added optional support for the <em>libfdk-aac</em> encoder, using the <a href="https://github.com/nu774/fdkaac">fdkaac</a> front-end by nu774<br /></li>
 <li>Added detection of the <em>64-Bit</em> version of QAAC encoder, requires 64-Bit Apple Application Support<br /></li>
 <li>Added enhanced file renaming option: Default file extensions can now be overwritten<br /></li>
index 69b6283..caf9379 100644 (file)
@@ -6,7 +6,7 @@
 
 * Upgraded build environment to Microsoft Visual Studio 2013 with Update-5
 * Updated Qt runtime libraries to v4.8.7 Final (2015-05-25), compiled with MSVC 12.0
-* Added Hungarian translation, contributed by Zityi's Translator Team <zityisoft@gmail.com>
+* Added Hungarian translation, contributed by Zityi's Translator Team <<zityisoft@gmail.com>>
 * Added optional support for the *libfdk-aac* encoder, using the [fdkaac](https://github.com/nu774/fdkaac) front-end by nu774
 * Added detection of the *64-Bit* version of QAAC encoder, requires 64-Bit Apple Application Support
 * Added enhanced file renaming option: Default file extensions can now be overwritten
index b7e21bf..5080352 100644 (file)
@@ -526,6 +526,7 @@ FunctionEnd
        Delete ${options} "$INSTDIR\vcruntime*.dll"
        Delete ${options} "$INSTDIR\vccorlib*.dll"
        
+       RMDir /r ${options} "$INSTDIR\cache"
        RMDir /r ${options} "$INSTDIR\img"
        RMDir /r ${options} "$INSTDIR\imageformats"
        RMDir /r ${options} "$INSTDIR\redist"
index bb8b39e..c7a2399 100644 (file)
@@ -35,7 +35,7 @@
 #define VER_LAMEXP_MINOR_LO                                    2
 #define VER_LAMEXP_TYPE                                                Beta
 #define VER_LAMEXP_PATCH                                       6
-#define VER_LAMEXP_BUILD                                       1798
+#define VER_LAMEXP_BUILD                                       1800
 #define VER_LAMEXP_CONFG                                       1700
 
 ///////////////////////////////////////////////////////////////////////////////
index 420d3bf..7b2e069 100644 (file)
@@ -815,7 +815,7 @@ void AboutDialog::initSoftwareTab(void)
                tr("dcaenc"),
                "dcaenc.exe", "????-??-??",
                tr("Copyright (c) 2008-2011 Alexander E. Patrakov. Distributed under the LGPL."),
-               "http://gitorious.org/dtsenc/dtsenc/trees/master"
+               "https://gitlab.com/patrakov/dcaenc"
        );
        moreAboutText += makeToolText
        (
diff --git a/src/FileHash.cpp b/src/FileHash.cpp
new file mode 100644 (file)
index 0000000..405d3eb
--- /dev/null
@@ -0,0 +1,68 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2015 LoRd_MuldeR <MuldeR2@GMX.de>
+//
+// 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
+// (at your option) any later version, but always including the *additional*
+// restrictions defined in the "License.txt" file.
+//
+// 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 "FileHash.h"
+
+//MUtils
+#include <MUtils/Hash_Keccak.h>
+#include <MUtils/Exception.h>
+
+static const char *g_blnk = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+static const char *g_seed = "c375d83b4388329408dfcbb4d9a065b6e06d28272f25ef299c70b506e26600af79fd2f866ae24602daf38f25c9d4b7e1";
+static const char *g_salt = "ee9f7bdabc170763d2200a7e3030045aafe380011aefc1730e547e9244c62308aac42a976feeca224ba553de0c4bb883";
+
+QByteArray FileHash::computeHash(QFile &file)
+{
+       QByteArray hash = QByteArray::fromHex(g_blnk);
+
+       if(file.isOpen() && file.reset())
+       {
+               MUtils::Hash::Keccak keccak;
+
+               const QByteArray data = file.readAll();
+               const QByteArray seed = QByteArray::fromHex(g_seed);
+               const QByteArray salt = QByteArray::fromHex(g_salt);
+       
+               if(keccak.init(MUtils::Hash::Keccak::hb384))
+               {
+                       bool ok = true;
+                       ok = ok && keccak.addData(seed);
+                       ok = ok && keccak.addData(data);
+                       ok = ok && keccak.addData(salt);
+                       if(ok)
+                       {
+                               const QByteArray digest = keccak.finalize();
+                               if(!digest.isEmpty()) hash = digest.toHex();
+                       }
+               }
+       }
+
+       return hash;
+}
+
+void FileHash::selfTest(void)
+{
+       if(!MUtils::Hash::Keccak::selfTest())
+       {
+               MUTILS_THROW("QKeccakHash self-test has failed!");
+       }
+}
diff --git a/src/FileHash.h b/src/FileHash.h
new file mode 100644 (file)
index 0000000..adbbc63
--- /dev/null
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2015 LoRd_MuldeR <MuldeR2@GMX.de>
+//
+// 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
+// (at your option) any later version, but always including the *additional*
+// restrictions defined in the "License.txt" file.
+//
+// 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
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include <QFile>
+#include <QByteArray>
+
+class FileHash
+{
+public:
+       static QByteArray computeHash(QFile &file);
+       static void selfTest(void);
+private:
+       FileHash()  {}
+       ~FileHash() {};
+};
+
index 799bd68..7a74dd3 100644 (file)
@@ -94,6 +94,11 @@ void lamexp_tools_register(const QString &toolName, LockedFile *const file, cons
 {
        QWriteLocker writeLock(&g_lamexp_tools_lock);
        
+       if(!file)
+       {
+               MUTILS_THROW("lamexp_register_tool: Tool file must not be NULL!");
+       }
+
        if(g_lamexp_tools_data.isNull())
        {
                g_lamexp_tools_data.reset(new tool_hash_t());
index 24770e7..0c45502 100644 (file)
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "LockedFile.h"
+
+//Internal
 #include "Global.h"
+#include "FileHash.h"
 
 //MUtils
 #include <MUtils/OSSupport.h>
-#include <MUtils/Hash_Keccak.h>
 #include <MUtils/Exception.h>
 
 //Qt
@@ -35,6 +37,7 @@
 #include <QDir>
 #include <QCryptographicHash>
 
+//CRT
 #include <stdio.h>
 #include <io.h>
 #include <fcntl.h>
@@ -67,63 +70,19 @@ static void CLOSE_HANDLE(HANDLE &h)
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static const char *g_blnk = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
-static const char *g_seed = "c375d83b4388329408dfcbb4d9a065b6e06d28272f25ef299c70b506e26600af79fd2f866ae24602daf38f25c9d4b7e1";
-static const char *g_salt = "ee9f7bdabc170763d2200a7e3030045aafe380011aefc1730e547e9244c62308aac42a976feeca224ba553de0c4bb883";
-
-QByteArray LockedFile::fileHash(QFile &file)
+static __forceinline void doWriteOutput(QFile &outFile, const QResource *const resource)
 {
-       QByteArray hash = QByteArray::fromHex(g_blnk);
-
-       if(file.isOpen() && file.reset())
+       for(int i = 0; i < 64; i++)
        {
-               MUtils::Hash::Keccak keccak;
-
-               const QByteArray data = file.readAll();
-               const QByteArray seed = QByteArray::fromHex(g_seed);
-               const QByteArray salt = QByteArray::fromHex(g_salt);
-       
-               if(keccak.init(MUtils::Hash::Keccak::hb384))
+               if(outFile.open(QIODevice::WriteOnly))
                {
-                       bool ok = true;
-                       ok = ok && keccak.addData(seed);
-                       ok = ok && keccak.addData(data);
-                       ok = ok && keccak.addData(salt);
-                       if(ok)
-                       {
-                               const QByteArray digest = keccak.finalize();
-                               if(!digest.isEmpty()) hash = digest.toHex();
-                       }
+                       break;
                }
-       }
-
-       return hash;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-LockedFile::LockedFile(QResource *const resource, const QString &outPath, const QByteArray &expectedHash, const bool bOwnsFile)
-:
-       m_bOwnsFile(bOwnsFile),
-       m_filePath(QFileInfo(outPath).absoluteFilePath())
-{
-       m_fileDescriptor = -1;
-       HANDLE fileHandle = NULL;
-               
-       //Make sure the resource is valid
-       if(!(resource->isValid() && resource->data()))
-       {
-               MUTILS_THROW_FMT("The resource at %p is invalid!", resource);
-       }
-
-       QFile outFile(m_filePath);
-       
-       //Open output file
-       for(int i = 0; i < 64; i++)
-       {
-               if(outFile.open(QIODevice::WriteOnly)) break;
-               if(!i) qWarning("Failed to open file on first attemp, retrying...");
-               Sleep(100);
+               if(i == 0)
+               {
+                       qWarning("Failed to open file on first attemp, retrying...");
+               }
+               Sleep(25);
        }
        
        //Write data to file
@@ -142,40 +101,68 @@ LockedFile::LockedFile(QResource *const resource, const QString &outPath, const
 
        //Close file after it has been written
        outFile.close();
+}
 
-       //Now lock the file!
+static __forceinline void doValidateFileExists(const QString &filePath)
+{
+       QFileInfo existingFileInfo(filePath);
+       existingFileInfo.setCaching(false);
+       
+       //Make sure the file exists, before we try to lock it
+       if((!existingFileInfo.exists()) || (!existingFileInfo.isFile()) || filePath.isEmpty())
+       {
+               MUTILS_THROW_FMT("File '%s' does not exist!", MUTILS_UTF8(filePath));
+       }
+}
+
+static __forceinline void doLockFile(HANDLE &fileHandle, const QString &filePath, QFile *const outFile)
+{
        for(int i = 0; i < 64; i++)
        {
-               fileHandle = CreateFileW(MUTILS_WCHR(QDir::toNativeSeparators(m_filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
-               if(VALID_HANDLE(fileHandle)) break;
-               if(!i) qWarning("Failed to lock file on first attemp, retrying...");
-               Sleep(100);
+               fileHandle = CreateFileW(MUTILS_WCHR(QDir::toNativeSeparators(filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
+               if(VALID_HANDLE(fileHandle))
+               {
+                       break;
+               }
+               if(i == 0)
+               {
+                       qWarning("Failed to lock file on first attemp, retrying...");
+               }
+               Sleep(25);
        }
        
        //Locked successfully?
        if(!VALID_HANDLE(fileHandle))
        {
-               QFile::remove(QFileInfo(outFile).canonicalFilePath());
-               MUTILS_THROW_FMT("File '%s' could not be locked!", MUTILS_UTF8(QFileInfo(m_filePath).fileName()));
+               if(outFile)
+               {
+                       QFile::remove(QFileInfo(*outFile).canonicalFilePath());
+               }
+               MUTILS_THROW_FMT("File '%s' could not be locked!", MUTILS_UTF8(QFileInfo(filePath).fileName()));
        }
+}
 
-       //Get file descriptor
-       m_fileDescriptor = _open_osfhandle(reinterpret_cast<intptr_t>(fileHandle), _O_RDONLY | _O_BINARY);
-       if(m_fileDescriptor < 0)
+static __forceinline void doInitFileDescriptor(const HANDLE &fileHandle, int &fileDescriptor)
+{
+       fileDescriptor = _open_osfhandle(reinterpret_cast<intptr_t>(fileHandle), _O_RDONLY | _O_BINARY);
+       if(fileDescriptor < 0)
        {
                MUTILS_THROW_FMT("Failed to obtain C Runtime file descriptor!");
        }
+}
 
+static __forceinline void doValidateHash(HANDLE &fileHandle, const int &fileDescriptor, const QByteArray &expectedHash, const QString &filePath)
+{
        QFile checkFile;
 
        //Now re-open the file for reading
        if(g_useFileDescrForQFile)
        {
-               checkFile.open(m_fileDescriptor, QIODevice::ReadOnly);
+               checkFile.open(fileDescriptor, QIODevice::ReadOnly);
        }
        else
        {
-               checkFile.setFileName(m_filePath);
+               checkFile.setFileName(filePath);
                for(int i = 0; i < 64; i++)
                {
                        if(checkFile.open(QIODevice::ReadOnly)) break;
@@ -187,12 +174,12 @@ LockedFile::LockedFile(QResource *const resource, const QString &outPath, const
        //Opened successfully
        if(!checkFile.isOpen())
        {
-               QFile::remove(m_filePath);
-               MUTILS_THROW_FMT("File '%s' could not be read!", MUTILS_UTF8(QFileInfo(m_filePath).fileName()));
+               QFile::remove(filePath);
+               MUTILS_THROW_FMT("File '%s' could not be read!", MUTILS_UTF8(QFileInfo(filePath).fileName()));
        }
 
        //Verify file contents
-       const QByteArray hash = fileHash(checkFile);
+       const QByteArray hash = FileHash::computeHash(checkFile);
        checkFile.close();
 
        //Compare hashes
@@ -200,49 +187,78 @@ LockedFile::LockedFile(QResource *const resource, const QString &outPath, const
        {
                qWarning("\nFile checksum error:\n A = %s\n B = %s\n", expectedHash.constData(), hash.constData());
                CLOSE_HANDLE(fileHandle);
-               QFile::remove(m_filePath);
-               MUTILS_THROW_FMT("File '%s' is corruputed, take care!", MUTILS_UTF8(QFileInfo(m_filePath).fileName()));
+               QFile::remove(filePath);
+               MUTILS_THROW_FMT("File '%s' is corruputed, take care!", MUTILS_UTF8(QFileInfo(filePath).fileName()));
        }
 }
 
-LockedFile::LockedFile(const QString &filePath, const bool bOwnsFile)
+///////////////////////////////////////////////////////////////////////////////
+
+LockedFile::LockedFile(QResource *const resource, const QString &outPath, const QByteArray &expectedHash, const bool bOwnsFile)
 :
        m_bOwnsFile(bOwnsFile),
-       m_filePath(QFileInfo(filePath).canonicalFilePath())
+       m_filePath(QFileInfo(outPath).absoluteFilePath())
 {
        m_fileDescriptor = -1;
        HANDLE fileHandle = NULL;
+               
+       //Make sure the resource is valid
+       if(!(resource->isValid() && resource->data()))
+       {
+               MUTILS_THROW_FMT("The resource at %p is invalid!", resource);
+       }
 
-       QFileInfo existingFileInfo(filePath);
-       existingFileInfo.setCaching(false);
+       //Write data to output file
+       QFile outFile(m_filePath);
+       doWriteOutput(outFile, resource);
+
+       //Now lock the file!
+       doLockFile(fileHandle, m_filePath, &outFile);
+
+       //Get file descriptor
+       doInitFileDescriptor(fileHandle, m_fileDescriptor);
+
+       //Validate file hash
+       doValidateHash(fileHandle, m_fileDescriptor, expectedHash, m_filePath);
+}
+
+LockedFile::LockedFile(const QString &filePath, const QByteArray &expectedHash, const bool bOwnsFile)
+:
+       m_bOwnsFile(bOwnsFile),
+       m_filePath(QFileInfo(filePath).absoluteFilePath())
+{
+       m_fileDescriptor = -1;
+       HANDLE fileHandle = NULL;
        
        //Make sure the file exists, before we try to lock it
-       if((!existingFileInfo.exists()) || (!existingFileInfo.isFile()) || m_filePath.isEmpty())
-       {
-               MUTILS_THROW_FMT("File '%s' does not exist!", MUTILS_UTF8(filePath));
-       }
+       doValidateFileExists(m_filePath);
+
+       //Now lock the file!
+       doLockFile(fileHandle, m_filePath, NULL);
+
+       //Get file descriptor
+       doInitFileDescriptor(fileHandle, m_fileDescriptor);
+
+       //Validate file hash
+       doValidateHash(fileHandle, m_fileDescriptor, expectedHash, m_filePath);
+}
+
+LockedFile::LockedFile(const QString &filePath, const bool bOwnsFile)
+:
+       m_bOwnsFile(bOwnsFile),
+       m_filePath(QFileInfo(filePath).canonicalFilePath())
+{
+       m_fileDescriptor = -1;
+       HANDLE fileHandle = NULL;
        
-       //Now lock the file
-       for(int i = 0; i < 64; i++)
-       {
-               fileHandle = CreateFileW(MUTILS_WCHR(QDir::toNativeSeparators(m_filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
-               if(VALID_HANDLE(fileHandle)) break;
-               if(!i) qWarning("Failed to lock file on first attemp, retrying...");
-               Sleep(100);
-       }
+       //Make sure the file exists, before we try to lock it
+       doValidateFileExists(m_filePath);
 
-       //Locked successfully?
-       if(!VALID_HANDLE(fileHandle))
-       {
-               MUTILS_THROW_FMT("File '%s' could not be locked!", MUTILS_UTF8(QFileInfo(m_filePath).fileName()));
-       }
+       //Now lock the file!
+       doLockFile(fileHandle, m_filePath, NULL);
 
        //Get file descriptor
-       m_fileDescriptor = _open_osfhandle(reinterpret_cast<intptr_t>(fileHandle), _O_RDONLY | _O_BINARY);
-       if(m_fileDescriptor < 0)
-       {
-               MUTILS_THROW_FMT("Failed to obtain C Runtime file descriptor!");
-       }
+       doInitFileDescriptor(fileHandle, m_fileDescriptor);
 }
 
 LockedFile::~LockedFile(void)
@@ -269,11 +285,3 @@ const QString &LockedFile::filePath()
 {
        return m_filePath;
 }
-
-void LockedFile::selfTest()
-{
-       if(!MUtils::Hash::Keccak::selfTest())
-       {
-               MUTILS_THROW("QKeccakHash self-test has failed!");
-       }
-}
index 77b49ff..e5eb42e 100644 (file)
@@ -31,14 +31,12 @@ class LockedFile
 {
 public:
        LockedFile(QResource *const resource, const QString &outPath, const QByteArray &expectedHash = QByteArray(), const bool bOwnsFile = true);
+       LockedFile(const QString &filePath, const QByteArray &expectedHash, const bool bOwnsFile = false);
        LockedFile(const QString &filePath, const bool bOwnsFile = false);
        ~LockedFile(void);
 
        const QString &filePath();
 
-       static void selfTest();
-       static QByteArray fileHash(QFile &file);
-
 private:
        const bool m_bOwnsFile;
        const QString m_filePath;
index 2598b65..3916244 100644 (file)
@@ -26,6 +26,7 @@
 #define LAMEXP_INC_TOOLS 1
 #include "Tools.h"
 #include "LockedFile.h"
+#include "FileHash.h"
 #include "Tool_Abstract.h"
 
 //MUtils
@@ -49,6 +50,9 @@
 #include <QElapsedTimer>
 #include <QVector>
 
+/* enable custom tools? */
+static const bool ENABLE_CUSTOM_TOOLS = true;
+
 /* helper macros */
 #define PRINT_CPU_TYPE(X) case X: qDebug("Selected CPU is: " #X)
 #define MAKE_REGEXP(STR) (((STR) && ((STR)[0])) ? QRegExp((STR)) : QRegExp())
@@ -208,28 +212,58 @@ public:
 protected:
        void taskMain(void)
        {
-               LockedFile *lockedFile = NULL;
+               QScopedPointer<LockedFile> lockedFile;
                unsigned int version = m_toolVersion;
 
-               QFileInfo toolFileInfo(m_toolName);
-               const QString toolShortName = QString("%1.%2").arg(toolFileInfo.baseName().toLower(), toolFileInfo.suffix().toLower());
+               const QFileInfo toolFileInfo(m_toolName);
+               const QString   toolShrtName = QString("%1.%2").arg(toolFileInfo.baseName().toLower(), toolFileInfo.suffix().toLower());
 
-               QFileInfo customTool(QString("%1/tools/%2/%3").arg(m_appDir.canonicalPath(), QString::number(lamexp_version_build()), toolShortName));
-               if(customTool.exists() && customTool.isFile())
+               //Try to load a "custom" tool first
+               if(ENABLE_CUSTOM_TOOLS)
                {
-                       qDebug("Setting up file: %s <- %s", toolShortName.toLatin1().constData(), m_appDir.relativeFilePath(customTool.canonicalFilePath()).toLatin1().constData());
-                       lockedFile = new LockedFile(customTool.canonicalFilePath()); version = UINT_MAX; s_bCustom = true;
+                       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();
+                               }
+                       }
                }
-               else
+
+               //Try to load the tool from the "cache" next
+               if(lockedFile.isNull())
                {
-                       qDebug("Extracting file: %s -> %s", m_toolName.toLatin1().constData(), toolShortName.toLatin1().constData());
-                       lockedFile = new LockedFile(m_toolResource.data(), QString("%1/lxp_%2").arg(MUtils::temp_folder(), toolShortName), m_toolHash);
+                       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();
+                               }
+                       }
                }
 
-               if(lockedFile)
+               //If still not initialized, extract tool now!
+               if(lockedFile.isNull())
                {
-                       lamexp_tools_register(toolShortName, lockedFile, version, m_toolTag);
+                       qDebug("Extracting file: %s -> %s", m_toolName.toLatin1().constData(), toolShrtName.toLatin1().constData());
+                       lockedFile.reset(new LockedFile(m_toolResource.data(), QString("%1/lxp_%2").arg(MUtils::temp_folder(), toolShrtName), m_toolHash));
                }
+
+               //Register tool
+               lamexp_tools_register(toolShrtName, lockedFile.take(), version, m_toolTag);
        }
 
 private:
@@ -379,7 +413,7 @@ double InitializationThread::doInit(const size_t threadCount)
        pool->setMaxThreadCount((threadCount > 0) ? threadCount : qBound(2U, cores2threads(m_cpuFeatures.count), EXPECTED_TOOL_COUNT));
        /* qWarning("Using %u threads for extraction.", pool->maxThreadCount()); */
 
-       LockedFile::selfTest();
+       FileHash::selfTest();
        ExtractorTask::clearFlags();
 
        //Start the timer
@@ -697,7 +731,7 @@ void InitializationThread::selfTest(void)
 {
        const unsigned int cpu[4] = {CPU_TYPE_X86_GEN, CPU_TYPE_X86_SSE, CPU_TYPE_X64_GEN, CPU_TYPE_X64_SSE};
 
-       LockedFile::selfTest();
+       FileHash::selfTest();
 
        for(size_t k = 0; k < 4; k++)
        {
@@ -730,7 +764,7 @@ void InitializationThread::selfTest(void)
                                                qFatal("The resource for \"%s\" could not be opened!", MUTILS_UTF8(toolName));
                                                break;
                                        }
-                                       QByteArray hash = LockedFile::fileHash(resource);
+                                       QByteArray hash = FileHash::computeHash(resource);
                                        if(hash.isNull() || _stricmp(hash.constData(), expectedHash.constData()))
                                        {
                                                qFatal("Hash check for tool \"%s\" has failed!", MUTILS_UTF8(toolName));