diff --git a/LameXP_VS2013.vcxproj b/LameXP_VS2013.vcxproj
index 461e5bdf..7e3f6528 100644
--- a/LameXP_VS2013.vcxproj
+++ b/LameXP_VS2013.vcxproj
@@ -327,7 +327,12 @@ del "$(TargetDir)imageformats\q???d4.dll"
-
+
+
+
+
+
+
diff --git a/LameXP_VS2013.vcxproj.filters b/LameXP_VS2013.vcxproj.filters
index 927a1fe0..863d7a9d 100644
--- a/LameXP_VS2013.vcxproj.filters
+++ b/LameXP_VS2013.vcxproj.filters
@@ -1,9 +1,6 @@

-
- Source Files
-
Source Files
@@ -400,6 +397,24 @@
Generated Files\QRC
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
diff --git a/etc/Translation/Blank.ts b/etc/Translation/Blank.ts
index 7e7c3c0b..a4162abe 100644
--- a/etc/Translation/Blank.ts
+++ b/etc/Translation/Blank.ts
@@ -3300,22 +3300,22 @@
QApplication
-
+
-
+
-
+
-
+
diff --git a/etc/Translation/LameXP_PL.ts b/etc/Translation/LameXP_PL.ts
index 86e45880..05a90c64 100644
--- a/etc/Translation/LameXP_PL.ts
+++ b/etc/Translation/LameXP_PL.ts
@@ -3337,22 +3337,22 @@
QApplication
-
+
Plik wykonywalny '%1' nie działa w trybie kompatybilności z Windows.
-
+
Plik wykonywalny '%1' wymaga Qt v%2, znaleziono jednak Qt v%3.
-
+
Plik wykonywalny "%1" został skompilowany dla Qt "%2", znaleziono "%3".
-
+
diff --git a/etc/Translation/LameXP_SV.ts b/etc/Translation/LameXP_SV.ts
index d64a69a6..82346cd3 100644
--- a/etc/Translation/LameXP_SV.ts
+++ b/etc/Translation/LameXP_SV.ts
@@ -3320,22 +3320,22 @@
QApplication
-
+
EXE-filen '%1' stöder inte Windows kompatibilitetsläge.
-
+
EXE-filen '%1' kräver Qt v%2, du har Qt v%3.
-
+
EXE-filen '%1' är byggd för Qt '%2', du har Qt '%3'.
-
+
diff --git a/src/Config.h b/src/Config.h
index 4af7be98..108cf6ce 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -35,7 +35,7 @@
#define VER_LAMEXP_MINOR_LO 9
#define VER_LAMEXP_TYPE Alpha
#define VER_LAMEXP_PATCH 7
-#define VER_LAMEXP_BUILD 1450
+#define VER_LAMEXP_BUILD 1454
#define VER_LAMEXP_CONFG 1348
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/Global.h b/src/Global.h
index 018b2a66..bebdf305 100644
--- a/src/Global.h
+++ b/src/Global.h
@@ -22,18 +22,10 @@
#pragma once
-//Target version
-#include "Targetver.h"
-
-//inlcude C standard library
#define _CRT_RAND_S
-#include
-#include
+#include
-//Visual Leaks Detector
-#include
-
-//Declarations
+//Forward declarations
class QString;
class QStringList;
class QDate;
@@ -44,7 +36,15 @@ class QProcess;
class LockedFile;
enum QtMsgType;
-//Types definitions
+//Variables
+extern const char* LAMEXP_DEFAULT_LANGID;
+extern const char* LAMEXP_DEFAULT_TRANSLATION;
+
+///////////////////////////////////////////////////////////////////////////////
+// TYPE DEFINITIONS
+///////////////////////////////////////////////////////////////////////////////
+
+//CPU features
typedef struct
{
int family;
@@ -125,119 +125,123 @@ typedef enum
}
lamexp_network_t;
-//LameXP version info
-unsigned int lamexp_version_major(void);
-unsigned int lamexp_version_minor(void);
-unsigned int lamexp_version_build(void);
-unsigned int lamexp_version_confg(void);
-const QDate &lamexp_version_date(void);
-const char *lamexp_version_time(void);
-const char *lamexp_version_release(void);
-bool lamexp_version_demo(void);
-const char *lamexp_version_compiler(void);
-const char *lamexp_version_arch(void);
-QDate lamexp_version_expires(void);
-unsigned int lamexp_toolver_neroaac(void);
-unsigned int lamexp_toolver_fhgaacenc(void);
-unsigned int lamexp_toolver_qaacenc(void);
-unsigned int lamexp_toolver_coreaudio(void);
-const char *lamexp_website_url(void);
-const char *lamexp_mulders_url(void);
-const char *lamexp_support_url(void);
-const lamexp_os_version_t &lamexp_get_os_version(void);
-bool lamexp_detect_wine(void);
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////
-//Public functions
-void lamexp_init_console(const QStringList &argv);
-bool lamexp_init_qt(int argc, char* argv[]);
-int lamexp_init_ipc(void);
-void lamexp_invalid_param_handler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
-void lamexp_message_handler(QtMsgType type, const char *msg);
-void lamexp_register_tool(const QString &toolName, LockedFile *file, unsigned int version = 0, const QString *tag = NULL);
-bool lamexp_check_tool(const QString &toolName);
-const QString lamexp_lookup_tool(const QString &toolName);
-unsigned int lamexp_tool_version(const QString &toolName, QString *tag = NULL);
-void lamexp_finalization(void);
-QString lamexp_rand_str(const bool bLong = false);
-const QString &lamexp_temp_folder2(void);
-void lamexp_ipc_read(unsigned int *command, char* message, size_t buffSize);
-void lamexp_ipc_send(unsigned int command, const char* message);
-lamexp_cpu_t lamexp_detect_cpu_features(const QStringList &argv);
-bool lamexp_portable_mode(void);
-bool lamexp_shutdown_computer(const QString &message, const unsigned long timeout = 30, const bool forceShutdown = true, const bool hibernate = false);
-bool lamexp_is_hibernation_supported(void);
QIcon lamexp_app_icon(const QDate *date = NULL, const QTime *time = NULL);
+bool lamexp_append_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text);
const QStringList &lamexp_arguments(void);
-
-//Translation support
-QStringList lamexp_query_translations(void);
-bool lamexp_translation_register(const QString &langId, const QString &qmFile, const QString &langName, unsigned int &systemId, unsigned int &country);
-QString lamexp_translation_name(const QString &language);
-unsigned int lamexp_translation_sysid(const QString &langId);
-unsigned int lamexp_translation_country(const QString &langId);
-bool lamexp_install_translator_from_file(const QString &qmFile);
-bool lamexp_install_translator(const QString &language);
QStringList lamexp_available_codepages(bool noAliases = true);
-extern const char* LAMEXP_DEFAULT_LANGID;
-extern const char* LAMEXP_DEFAULT_TRANSLATION;
-
-//Auxiliary functions
-bool lamexp_clean_folder(const QString &folderPath);
-const QString lamexp_version2string(const QString &pattern, unsigned int version, const QString &defaultText, const QString *tag = NULL);
-const QString &lamexp_known_folder(lamexp_known_folder_t folder_id);
-unsigned __int64 lamexp_free_diskspace(const QString &path, bool *ok = NULL);
-bool lamexp_remove_file(const QString &filename);
-bool lamexp_themes_enabled(void);
+bool lamexp_beep(int beepType);
void lamexp_blink_window(QWidget *poWindow, unsigned int count = 10, unsigned int delay = 150);
+bool lamexp_bring_process_to_front(const unsigned long pid);
+bool lamexp_bring_to_front(const QWidget *win);
+bool lamexp_broadcast(int eventType, bool onlyToVisible);
+bool lamexp_change_process_priority(const int priority);
+bool lamexp_change_process_priority(void *hProcess, const int priority);
+bool lamexp_change_process_priority(const QProcess *proc, const int priority);
+bool lamexp_check_escape_state(void);
+bool lamexp_check_sysmenu_msg(void *message, const unsigned int identifier);
+bool lamexp_check_tool(const QString &toolName);
const QString lamexp_clean_filename(const QString &str);
const QString lamexp_clean_filepath(const QString &str);
-void lamexp_seed_rand(void);
-unsigned int lamexp_rand(void);
+void lamexp_clean_all_tools(void);
+void lamexp_clean_all_translations(void);
+bool lamexp_clean_folder(const QString &folderPath);
QDate lamexp_current_date_safe(void);
-void lamexp_sleep(const unsigned int delay);
-bool lamexp_beep(int beepType);
-bool lamexp_play_sound(const unsigned short uiSoundIdx, const bool bAsync, const wchar_t *alias = NULL);
-bool lamexp_play_sound_file(const QString &library, const unsigned short uiSoundIdx, const bool bAsync);
+unsigned __int64 lamexp_current_file_time(void);
+void lamexp_dbg_dbg_output_string(const char* format, ...);
+unsigned long lamexp_dbg_private_bytes(void);
+lamexp_cpu_t lamexp_detect_cpu_features(const QStringList &argv);
+bool lamexp_detect_wine(void);
+bool lamexp_enable_close_button(const QWidget *win, const bool bEnable = true);
bool lamexp_exec_shell(const QWidget *win, const QString &url, const bool explore = false);
bool lamexp_exec_shell(const QWidget *win, const QString &url, const QString ¶meters, const QString &directory, const bool explore = false);
-__int64 lamexp_perfcounter_frequ(void);
-__int64 lamexp_perfcounter_value(void);
-bool lamexp_append_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text);
-bool lamexp_update_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text);
-bool lamexp_check_sysmenu_msg(void *message, const unsigned int identifier);
-bool lamexp_enable_close_button(const QWidget *win, const bool bEnable = true);
-bool lamexp_check_escape_state(void);
-bool lamexp_change_process_priority(const int priority);
-bool lamexp_change_process_priority(const QProcess *proc, const int priority);
-bool lamexp_change_process_priority(void *hProcess, const int priority);
-bool lamexp_bring_to_front(const QWidget *win);
-bool lamexp_bring_process_to_front(const unsigned long pid);
-int lamexp_network_status(void);
-unsigned long lamexp_process_id(const QProcess *proc);
-unsigned __int64 lamexp_current_file_time(void);
+void lamexp_fatal_exit(const wchar_t* exitMessage, const wchar_t* errorBoxMessage = NULL);
+void lamexp_finalization(void);
+unsigned __int64 lamexp_free_diskspace(const QString &path, bool *ok = NULL);
+const lamexp_os_version_t &lamexp_get_os_version(void);
+void lamexp_init_console(const QStringList &argv);
+void lamexp_init_error_handlers(void);
+int lamexp_init_ipc(void);
+void lamexp_init_process(QProcess &process, const QString &wokringDir);
+bool lamexp_init_qt(int argc, char* argv[]);
+bool lamexp_install_translator(const QString &language);
+bool lamexp_install_translator_from_file(const QString &qmFile);
+void lamexp_invalid_param_handler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
+void lamexp_ipc_exit(void);
+void lamexp_ipc_read(unsigned int *command, char* message, size_t buffSize);
+void lamexp_ipc_send(unsigned int command, const char* message);
+bool lamexp_is_hibernation_supported(void);
+const QString &lamexp_known_folder(lamexp_known_folder_t folder_id);
+const QString lamexp_lookup_tool(const QString &toolName);
+void lamexp_message_handler(QtMsgType type, const char *msg);
+const char *lamexp_mulders_url(void);
void lamexp_natural_string_sort(QStringList &list, const bool bIgnoreCase);
+int lamexp_network_status(void);
bool lamexp_open_media_file(const QString &mediaFilePath);
QString lamexp_path_to_short(const QString &longPath);
-void lamexp_init_process(QProcess &process, const QString &wokringDir);
-void lamexp_fatal_exit(const wchar_t* exitMessage, const wchar_t* errorBoxMessage = NULL);
+__int64 lamexp_perfcounter_frequ(void);
+__int64 lamexp_perfcounter_value(void);
+bool lamexp_play_sound(const unsigned short uiSoundIdx, const bool bAsync, const wchar_t *alias = NULL);
+bool lamexp_play_sound_file(const QString &library, const unsigned short uiSoundIdx, const bool bAsync);
+bool lamexp_portable_mode(void);
+unsigned long lamexp_process_id(const QProcess *proc);
+QStringList lamexp_query_translations(void);
+unsigned int lamexp_rand(void);
+QString lamexp_rand_str(const bool bLong = false);
+void lamexp_register_tool(const QString &toolName, LockedFile *file, unsigned int version = 0, const QString *tag = NULL);
+bool lamexp_remove_file(const QString &filename);
+void lamexp_seed_rand(void);
+bool lamexp_shutdown_computer(const QString &message, const unsigned long timeout = 30, const bool forceShutdown = true, const bool hibernate = false);
+void lamexp_sleep(const unsigned int delay);
+const char *lamexp_support_url(void);
+const QString &lamexp_temp_folder2(void);
+void lamexp_temp_folder_clear(void);
+bool lamexp_themes_enabled(void);
+unsigned int lamexp_tool_version(const QString &toolName, QString *tag = NULL);
+unsigned int lamexp_toolver_coreaudio(void);
+unsigned int lamexp_toolver_fhgaacenc(void);
+unsigned int lamexp_toolver_neroaac(void);
+unsigned int lamexp_toolver_qaacenc(void);
+unsigned int lamexp_translation_country(const QString &langId);
+bool lamexp_translation_init(void);
+QString lamexp_translation_name(const QString &language);
+bool lamexp_translation_register(const QString &langId, const QString &qmFile, const QString &langName, unsigned int &systemId, unsigned int &country);
+unsigned int lamexp_translation_sysid(const QString &langId);
+bool lamexp_update_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text);
+const QString lamexp_version2string(const QString &pattern, unsigned int version, const QString &defaultText, const QString *tag = NULL);
+const char *lamexp_version_arch(void);
+unsigned int lamexp_version_build(void);
+const char *lamexp_version_compiler(void);
+unsigned int lamexp_version_confg(void);
+const QDate &lamexp_version_date(void);
+bool lamexp_version_demo(void);
+QDate lamexp_version_expires(void);
+unsigned int lamexp_version_major(void);
+unsigned int lamexp_version_minor(void);
+const char *lamexp_version_release(void);
+const char *lamexp_version_time(void);
+const char *lamexp_website_url(void);
+///////////////////////////////////////////////////////////////////////////////
+// HELPER MACROS
+///////////////////////////////////////////////////////////////////////////////
-//Debug-only functions
-unsigned long lamexp_dbg_private_bytes(void);
-
-//Helper macros
+#define LAMEXP_BOOL2STR(X) ((X) ? "1" : "0")
+#define LAMEXP_COMPILER_WARNING(TXT) __pragma(message(__FILE__ "(" LAMEXP_MAKE_STRING(__LINE__) ") : warning: " TXT))
+#define LAMEXP_CLOSE(HANDLE) do { if(HANDLE != NULL && HANDLE != INVALID_HANDLE_VALUE) { CloseHandle(HANDLE); HANDLE = NULL; } } while(0)
#define LAMEXP_DELETE(PTR) do { if(PTR) { delete PTR; PTR = NULL; } } while(0)
#define LAMEXP_DELETE_ARRAY(PTR) do { if(PTR) { delete [] PTR; PTR = NULL; } } while(0)
-#define LAMEXP_SAFE_FREE(PTR) do { if(PTR) { free((void*) PTR); PTR = NULL; } } while(0)
-#define LAMEXP_CLOSE(HANDLE) do { if(HANDLE != NULL && HANDLE != INVALID_HANDLE_VALUE) { CloseHandle(HANDLE); HANDLE = NULL; } } while(0)
-#define QWCHAR(STR) (reinterpret_cast((STR).utf16()))
-#define WCHAR2QSTR(STR) (QString::fromUtf16(reinterpret_cast((STR))))
-#define QUTF8(STR) ((STR).toUtf8().constData())
-#define LAMEXP_BOOL2STR(X) ((X) ? "1" : "0")
#define LAMEXP_MAKE_STRING_EX(X) #X
#define LAMEXP_MAKE_STRING(X) LAMEXP_MAKE_STRING_EX(X)
-#define LAMEXP_COMPILER_WARNING(TXT) __pragma(message(__FILE__ "(" LAMEXP_MAKE_STRING(__LINE__) ") : warning: " TXT))
+#define LAMEXP_SAFE_FREE(PTR) do { if(PTR) { free((void*) PTR); PTR = NULL; } } while(0)
+#define LAMEXP_ZERO_MEMORY(X) memset(&(X), 0, sizeof((X)))
#define NOBR(STR) (QString("%1").arg((STR)).replace("-", "−"))
+#define QUTF8(STR) ((STR).toUtf8().constData())
+#define QWCHAR(STR) (reinterpret_cast((STR).utf16()))
+#define WCHAR2QSTR(STR) (QString::fromUtf16(reinterpret_cast((STR))))
//Check for debug build
#if defined(_DEBUG) && defined(QT_DEBUG) && !defined(NDEBUG) && !defined(QT_NO_DEBUG)
@@ -248,30 +252,6 @@ unsigned long lamexp_dbg_private_bytes(void);
#error Inconsistent debug defines detected!
#endif
-//Memory check
-#if LAMEXP_DEBUG
- #define LAMEXP_MEMORY_CHECK(FUNC, RETV, ...) do \
- { \
- SIZE_T _privateBytesBefore = lamexp_dbg_private_bytes(); \
- RETV = FUNC(__VA_ARGS__); \
- SIZE_T _privateBytesLeak = (lamexp_dbg_private_bytes() - _privateBytesBefore) / 1024; \
- if(_privateBytesLeak > 0) { \
- char _buffer[128]; \
- _snprintf_s(_buffer, 128, _TRUNCATE, "Memory leak: Lost %u KiloBytes of PrivateUsage memory.\n", _privateBytesLeak); \
- OutputDebugStringA("----------\n"); \
- OutputDebugStringA(_buffer); \
- OutputDebugStringA("----------\n"); \
- } \
- } \
- while(0)
-#else
- #define LAMEXP_MEMORY_CHECK(FUNC, RETV, ...) do \
- { \
- RETV = __noop(__VA_ARGS__); \
- } \
- while(0)
-#endif
-
//Check for CPU-compatibility options
#if !defined(_M_X64) && defined(_MSC_VER) && defined(_M_IX86_FP)
#if (_M_IX86_FP != 0)
@@ -292,3 +272,23 @@ while(0)
throw std::runtime_error(_error_msg); \
} \
while(0)
+
+//Memory check
+#if LAMEXP_DEBUG
+ #define LAMEXP_MEMORY_CHECK(FUNC, RETV, ...) do \
+ { \
+ size_t _privateBytesBefore = lamexp_dbg_private_bytes(); \
+ RETV = FUNC(__VA_ARGS__); \
+ size_t _privateBytesLeak = (lamexp_dbg_private_bytes() - _privateBytesBefore) / 1024; \
+ if(_privateBytesLeak > 0) { \
+ lamexp_dbg_dbg_output_string("\nMemory leak: Lost %u KiloBytes of PrivateUsage memory!\n\n", _privateBytesLeak); \
+ } \
+ } \
+ while(0)
+#else
+ #define LAMEXP_MEMORY_CHECK(FUNC, RETV, ...) do \
+ { \
+ RETV = __noop(__VA_ARGS__); \
+ } \
+ while(0)
+#endif
diff --git a/src/Global_EntryPoint.cpp b/src/Global_EntryPoint.cpp
new file mode 100644
index 00000000..29905233
--- /dev/null
+++ b/src/Global_EntryPoint.cpp
@@ -0,0 +1,79 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2013 LoRd_MuldeR
+//
+// 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 "Global.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////
+
+static size_t lamexp_entry_check(void);
+static size_t g_lamexp_entry_check_result = lamexp_entry_check();
+static size_t g_lamexp_entry_check_flag = 0x789E09B2;
+
+/*
+ * Entry point checks
+ */
+static size_t lamexp_entry_check(void)
+{
+ volatile size_t retVal = 0xA199B5AF;
+ if(g_lamexp_entry_check_flag != 0x8761F64D)
+ {
+ lamexp_fatal_exit(L"Application initialization has failed, take care!");
+ }
+ return retVal;
+}
+
+/*
+ * Application entry point (runs before static initializers)
+ */
+extern "C"
+{
+ int WinMainCRTStartup(void);
+
+ void _lamexp_global_init_win32(void);
+ void _lamexp_global_init_versn(void);
+ void _lamexp_global_init_tools(void);
+ void _lamexp_global_init_ipcom(void);
+ void _lamexp_global_init_utils(void);
+
+ int lamexp_entry_point(void)
+ {
+ if(g_lamexp_entry_check_flag != 0x789E09B2)
+ {
+ lamexp_fatal_exit(L"Application initialization has failed, take care!");
+ }
+
+ //Call global initialization functions
+ _lamexp_global_init_win32();
+ _lamexp_global_init_versn();
+ _lamexp_global_init_tools();
+ _lamexp_global_init_ipcom();
+ _lamexp_global_init_utils();
+
+ //Make sure we will pass the check
+ g_lamexp_entry_check_flag = (~g_lamexp_entry_check_flag);
+
+ //Now initialize the C Runtime library!
+ return WinMainCRTStartup();
+ }
+}
diff --git a/src/Global_IPC.cpp b/src/Global_IPC.cpp
new file mode 100644
index 00000000..5a5737d1
--- /dev/null
+++ b/src/Global_IPC.cpp
@@ -0,0 +1,278 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2013 LoRd_MuldeR
+//
+// 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 "Global.h"
+
+//Qt includes
+#include
+#include
+#include
+
+///////////////////////////////////////////////////////////////////////////////
+// TYPES
+///////////////////////////////////////////////////////////////////////////////
+
+static const size_t g_lamexp_ipc_slots = 128;
+
+typedef struct
+{
+ unsigned int command;
+ unsigned int reserved_1;
+ unsigned int reserved_2;
+ char parameter[4096];
+}
+lamexp_ipc_data_t;
+
+typedef struct
+{
+ unsigned int pos_write;
+ unsigned int pos_read;
+ lamexp_ipc_data_t data[g_lamexp_ipc_slots];
+}
+lamexp_ipc_t;
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL VARS
+///////////////////////////////////////////////////////////////////////////////
+
+//Shared memory
+static const struct
+{
+ char *sharedmem;
+ char *semaphore_read;
+ char *semaphore_read_mutex;
+ char *semaphore_write;
+ char *semaphore_write_mutex;
+}
+g_lamexp_ipc_uuid =
+{
+ "{21A68A42-6923-43bb-9CF6-64BF151942EE}",
+ "{7A605549-F58C-4d78-B4E5-06EFC34F405B}",
+ "{60AA8D04-F6B8-497d-81EB-0F600F4A65B5}",
+ "{726061D5-1615-4B82-871C-75FD93458E46}",
+ "{1A616023-AA6A-4519-8AF3-F7736E899977}"
+};
+static struct
+{
+ QSharedMemory *sharedmem;
+ QSystemSemaphore *semaphore_read;
+ QSystemSemaphore *semaphore_read_mutex;
+ QSystemSemaphore *semaphore_write;
+ QSystemSemaphore *semaphore_write_mutex;
+ QReadWriteLock lock;
+}
+g_lamexp_ipc_ptr;
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Initialize IPC
+ */
+int lamexp_init_ipc(void)
+{
+ QWriteLocker writeLock(&g_lamexp_ipc_ptr.lock);
+
+ if(g_lamexp_ipc_ptr.sharedmem && g_lamexp_ipc_ptr.semaphore_read && g_lamexp_ipc_ptr.semaphore_write && g_lamexp_ipc_ptr.semaphore_read_mutex && g_lamexp_ipc_ptr.semaphore_write_mutex)
+ {
+ return 0;
+ }
+
+ g_lamexp_ipc_ptr.semaphore_read = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_read), 0);
+ g_lamexp_ipc_ptr.semaphore_write = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_write), 0);
+ g_lamexp_ipc_ptr.semaphore_read_mutex = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_read_mutex), 0);
+ g_lamexp_ipc_ptr.semaphore_write_mutex = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_write_mutex), 0);
+
+ if(g_lamexp_ipc_ptr.semaphore_read->error() != QSystemSemaphore::NoError)
+ {
+ QString errorMessage = g_lamexp_ipc_ptr.semaphore_read->errorString();
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
+ qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage));
+ return -1;
+ }
+ if(g_lamexp_ipc_ptr.semaphore_write->error() != QSystemSemaphore::NoError)
+ {
+ QString errorMessage = g_lamexp_ipc_ptr.semaphore_write->errorString();
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
+ qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage));
+ return -1;
+ }
+ if(g_lamexp_ipc_ptr.semaphore_read_mutex->error() != QSystemSemaphore::NoError)
+ {
+ QString errorMessage = g_lamexp_ipc_ptr.semaphore_read_mutex->errorString();
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
+ qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage));
+ return -1;
+ }
+ if(g_lamexp_ipc_ptr.semaphore_write_mutex->error() != QSystemSemaphore::NoError)
+ {
+ QString errorMessage = g_lamexp_ipc_ptr.semaphore_write_mutex->errorString();
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
+ qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage));
+ return -1;
+ }
+
+ g_lamexp_ipc_ptr.sharedmem = new QSharedMemory(QString(g_lamexp_ipc_uuid.sharedmem), NULL);
+
+ if(!g_lamexp_ipc_ptr.sharedmem->create(sizeof(lamexp_ipc_t)))
+ {
+ if(g_lamexp_ipc_ptr.sharedmem->error() == QSharedMemory::AlreadyExists)
+ {
+ g_lamexp_ipc_ptr.sharedmem->attach();
+ if(g_lamexp_ipc_ptr.sharedmem->error() == QSharedMemory::NoError)
+ {
+ return 1;
+ }
+ else
+ {
+ QString errorMessage = g_lamexp_ipc_ptr.sharedmem->errorString();
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.sharedmem);
+ qFatal("Failed to attach to shared memory: %s", QUTF8(errorMessage));
+ return -1;
+ }
+ }
+ else
+ {
+ QString errorMessage = g_lamexp_ipc_ptr.sharedmem->errorString();
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.sharedmem);
+ qFatal("Failed to create shared memory: %s", QUTF8(errorMessage));
+ return -1;
+ }
+ }
+
+ memset(g_lamexp_ipc_ptr.sharedmem->data(), 0, sizeof(lamexp_ipc_t));
+ g_lamexp_ipc_ptr.semaphore_write->release(g_lamexp_ipc_slots);
+ g_lamexp_ipc_ptr.semaphore_read_mutex->release();
+ g_lamexp_ipc_ptr.semaphore_write_mutex->release();
+
+ return 0;
+}
+
+/*
+ * IPC send message
+ */
+void lamexp_ipc_send(unsigned int command, const char* message)
+{
+ QReadLocker readLock(&g_lamexp_ipc_ptr.lock);
+
+ if(!g_lamexp_ipc_ptr.sharedmem || !g_lamexp_ipc_ptr.semaphore_read || !g_lamexp_ipc_ptr.semaphore_write || !g_lamexp_ipc_ptr.semaphore_read_mutex || !g_lamexp_ipc_ptr.semaphore_write_mutex)
+ {
+ THROW("Shared memory for IPC not initialized yet.");
+ }
+
+ lamexp_ipc_data_t ipc_data;
+ memset(&ipc_data, 0, sizeof(lamexp_ipc_data_t));
+ ipc_data.command = command;
+
+ if(message)
+ {
+ strncpy_s(ipc_data.parameter, 4096, message, _TRUNCATE);
+ }
+
+ if(g_lamexp_ipc_ptr.semaphore_write->acquire())
+ {
+ if(g_lamexp_ipc_ptr.semaphore_write_mutex->acquire())
+ {
+ lamexp_ipc_t *ptr = reinterpret_cast(g_lamexp_ipc_ptr.sharedmem->data());
+ memcpy(&ptr->data[ptr->pos_write], &ipc_data, sizeof(lamexp_ipc_data_t));
+ ptr->pos_write = (ptr->pos_write + 1) % g_lamexp_ipc_slots;
+ g_lamexp_ipc_ptr.semaphore_read->release();
+ g_lamexp_ipc_ptr.semaphore_write_mutex->release();
+ }
+ }
+}
+
+/*
+ * IPC read message
+ */
+void lamexp_ipc_read(unsigned int *command, char* message, size_t buffSize)
+{
+ QReadLocker readLock(&g_lamexp_ipc_ptr.lock);
+
+ *command = 0;
+ message[0] = '\0';
+
+ if(!g_lamexp_ipc_ptr.sharedmem || !g_lamexp_ipc_ptr.semaphore_read || !g_lamexp_ipc_ptr.semaphore_write || !g_lamexp_ipc_ptr.semaphore_read_mutex || !g_lamexp_ipc_ptr.semaphore_write_mutex)
+ {
+ THROW("Shared memory for IPC not initialized yet.");
+ }
+
+ lamexp_ipc_data_t ipc_data;
+ memset(&ipc_data, 0, sizeof(lamexp_ipc_data_t));
+
+ if(g_lamexp_ipc_ptr.semaphore_read->acquire())
+ {
+ if(g_lamexp_ipc_ptr.semaphore_read_mutex->acquire())
+ {
+ lamexp_ipc_t *ptr = reinterpret_cast(g_lamexp_ipc_ptr.sharedmem->data());
+ memcpy(&ipc_data, &ptr->data[ptr->pos_read], sizeof(lamexp_ipc_data_t));
+ ptr->pos_read = (ptr->pos_read + 1) % g_lamexp_ipc_slots;
+ g_lamexp_ipc_ptr.semaphore_write->release();
+ g_lamexp_ipc_ptr.semaphore_read_mutex->release();
+
+ if(!(ipc_data.reserved_1 || ipc_data.reserved_2))
+ {
+ *command = ipc_data.command;
+ strncpy_s(message, buffSize, ipc_data.parameter, _TRUNCATE);
+ }
+ else
+ {
+ qWarning("Malformed IPC message, will be ignored");
+ }
+ }
+ }
+}
+
+/*
+ * Exit and clean-up IPC
+ */
+void lamexp_ipc_exit(void)
+{
+ if(g_lamexp_ipc_ptr.sharedmem) g_lamexp_ipc_ptr.sharedmem->detach();
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.sharedmem);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
+ LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+///////////////////////////////////////////////////////////////////////////////
+
+extern "C" void _lamexp_global_init_ipcom(void)
+{
+ LAMEXP_ZERO_MEMORY(g_lamexp_ipc_ptr);
+}
diff --git a/src/Global_Tools.cpp b/src/Global_Tools.cpp
new file mode 100644
index 00000000..0c9f5dd6
--- /dev/null
+++ b/src/Global_Tools.cpp
@@ -0,0 +1,398 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2013 LoRd_MuldeR
+//
+// 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 "Global.h"
+
+//Qt includes
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//LameXP includes
+#include "LockedFile.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL VARS
+///////////////////////////////////////////////////////////////////////////////
+
+//Tools
+static struct
+{
+ QMap *registry;
+ QMap *versions;
+ QMap *tags;
+ QReadWriteLock lock;
+}
+g_lamexp_tools;
+
+//Supported languages
+static struct
+{
+ QMap *files;
+ QMap *names;
+ QMap *sysid;
+ QMap *cntry;
+ QReadWriteLock lock;
+}
+g_lamexp_translation;
+
+//Translator
+static struct
+{
+ QTranslator *instance;
+ QReadWriteLock lock;
+}
+g_lamexp_currentTranslator;
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Register tool
+ */
+void lamexp_register_tool(const QString &toolName, LockedFile *file, unsigned int version, const QString *tag)
+{
+ QWriteLocker writeLock(&g_lamexp_tools.lock);
+
+ if(!g_lamexp_tools.registry) g_lamexp_tools.registry = new QMap();
+ if(!g_lamexp_tools.versions) g_lamexp_tools.versions = new QMap();
+ if(!g_lamexp_tools.tags) g_lamexp_tools.tags = new QMap();
+
+ if(g_lamexp_tools.registry->contains(toolName.toLower()))
+ {
+ THROW("lamexp_register_tool: Tool is already registered!");
+ }
+
+ g_lamexp_tools.registry->insert(toolName.toLower(), file);
+ g_lamexp_tools.versions->insert(toolName.toLower(), version);
+ g_lamexp_tools.tags->insert(toolName.toLower(), (tag) ? (*tag) : QString());
+}
+
+/*
+ * Check for tool
+ */
+bool lamexp_check_tool(const QString &toolName)
+{
+ QReadLocker readLock(&g_lamexp_tools.lock);
+ return (g_lamexp_tools.registry) ? g_lamexp_tools.registry->contains(toolName.toLower()) : false;
+}
+
+/*
+ * Lookup tool path
+ */
+const QString lamexp_lookup_tool(const QString &toolName)
+{
+ QReadLocker readLock(&g_lamexp_tools.lock);
+
+ if(g_lamexp_tools.registry)
+ {
+ if(g_lamexp_tools.registry->contains(toolName.toLower()))
+ {
+ return g_lamexp_tools.registry->value(toolName.toLower())->filePath();
+ }
+ else
+ {
+ return QString();
+ }
+ }
+ else
+ {
+ return QString();
+ }
+}
+
+/*
+ * Lookup tool version
+ */
+unsigned int lamexp_tool_version(const QString &toolName, QString *tag)
+{
+ QReadLocker readLock(&g_lamexp_tools.lock);
+ if(tag) tag->clear();
+
+ if(g_lamexp_tools.versions)
+ {
+ if(g_lamexp_tools.versions->contains(toolName.toLower()))
+ {
+ if(tag)
+ {
+ if(g_lamexp_tools.tags->contains(toolName.toLower())) *tag = g_lamexp_tools.tags->value(toolName.toLower());
+ }
+ return g_lamexp_tools.versions->value(toolName.toLower());
+ }
+ else
+ {
+ return UINT_MAX;
+ }
+ }
+ else
+ {
+ return UINT_MAX;
+ }
+}
+
+/*
+ * Version number to human-readable string
+ */
+const QString lamexp_version2string(const QString &pattern, unsigned int version, const QString &defaultText, const QString *tag)
+{
+ if(version == UINT_MAX)
+ {
+ return defaultText;
+ }
+
+ QString result = pattern;
+ int digits = result.count("?", Qt::CaseInsensitive);
+
+ if(digits < 1)
+ {
+ return result;
+ }
+
+ int pos = 0;
+ QString versionStr = QString().sprintf(QString().sprintf("%%0%du", digits).toLatin1().constData(), version);
+ int index = result.indexOf("?", Qt::CaseInsensitive);
+
+ while(index >= 0 && pos < versionStr.length())
+ {
+ result[index] = versionStr[pos++];
+ index = result.indexOf("?", Qt::CaseInsensitive);
+ }
+
+ if(tag)
+ {
+ result.replace(QChar('#'), *tag, Qt::CaseInsensitive);
+ }
+
+ return result;
+}
+
+/*
+ * Free all registered tools (final clean-up)
+ */
+void lamexp_clean_all_tools(void)
+{
+ if(g_lamexp_tools.registry)
+ {
+ QStringList keys = g_lamexp_tools.registry->keys();
+ for(int i = 0; i < keys.count(); i++)
+ {
+ LockedFile *lf = g_lamexp_tools.registry->take(keys.at(i));
+ LAMEXP_DELETE(lf);
+ }
+ g_lamexp_tools.registry->clear();
+ g_lamexp_tools.versions->clear();
+ g_lamexp_tools.tags->clear();
+ }
+
+ LAMEXP_DELETE(g_lamexp_tools.registry);
+ LAMEXP_DELETE(g_lamexp_tools.versions);
+ LAMEXP_DELETE(g_lamexp_tools.tags);
+}
+
+/*
+ * Initialize translations and add default language
+ */
+bool lamexp_translation_init(void)
+{
+ QWriteLocker writeLockTranslations(&g_lamexp_translation.lock);
+
+ if((!g_lamexp_translation.files) && (!g_lamexp_translation.names))
+ {
+ g_lamexp_translation.files = new QMap();
+ g_lamexp_translation.names = new QMap();
+ g_lamexp_translation.files->insert(LAMEXP_DEFAULT_LANGID, "");
+ g_lamexp_translation.names->insert(LAMEXP_DEFAULT_LANGID, "English");
+ return true;
+ }
+ else
+ {
+ qWarning("[lamexp_translation_init] Error: Already initialized!");
+ return false;
+ }
+}
+
+/*
+ * Register a new translation
+ */
+bool lamexp_translation_register(const QString &langId, const QString &qmFile, const QString &langName, unsigned int &systemId, unsigned int &country)
+{
+ QWriteLocker writeLockTranslations(&g_lamexp_translation.lock);
+
+ if(qmFile.isEmpty() || langName.isEmpty() || systemId < 1)
+ {
+ return false;
+ }
+
+ if(!g_lamexp_translation.files) g_lamexp_translation.files = new QMap();
+ if(!g_lamexp_translation.names) g_lamexp_translation.names = new QMap();
+ if(!g_lamexp_translation.sysid) g_lamexp_translation.sysid = new QMap();
+ if(!g_lamexp_translation.cntry) g_lamexp_translation.cntry = new QMap();
+
+ g_lamexp_translation.files->insert(langId, qmFile);
+ g_lamexp_translation.names->insert(langId, langName);
+ g_lamexp_translation.sysid->insert(langId, systemId);
+ g_lamexp_translation.cntry->insert(langId, country);
+
+ return true;
+}
+
+/*
+ * Get list of all translations
+ */
+QStringList lamexp_query_translations(void)
+{
+ QReadLocker readLockTranslations(&g_lamexp_translation.lock);
+ return (g_lamexp_translation.files) ? g_lamexp_translation.files->keys() : QStringList();
+}
+
+/*
+ * Get translation name
+ */
+QString lamexp_translation_name(const QString &langId)
+{
+ QReadLocker readLockTranslations(&g_lamexp_translation.lock);
+ return (g_lamexp_translation.names) ? g_lamexp_translation.names->value(langId.toLower(), QString()) : QString();
+}
+
+/*
+ * Get translation system id
+ */
+unsigned int lamexp_translation_sysid(const QString &langId)
+{
+ QReadLocker readLockTranslations(&g_lamexp_translation.lock);
+ return (g_lamexp_translation.sysid) ? g_lamexp_translation.sysid->value(langId.toLower(), 0) : 0;
+}
+
+/*
+ * Get translation script id
+ */
+unsigned int lamexp_translation_country(const QString &langId)
+{
+ QReadLocker readLockTranslations(&g_lamexp_translation.lock);
+ return (g_lamexp_translation.cntry) ? g_lamexp_translation.cntry->value(langId.toLower(), 0) : 0;
+}
+
+/*
+ * Install a new translator
+ */
+bool lamexp_install_translator(const QString &langId)
+{
+ bool success = false;
+ const QString qmFileToPath(":/localization/%1");
+
+ if(langId.isEmpty() || langId.toLower().compare(LAMEXP_DEFAULT_LANGID) == 0)
+ {
+ success = lamexp_install_translator_from_file(qmFileToPath.arg(LAMEXP_DEFAULT_TRANSLATION));
+ }
+ else
+ {
+ QReadLocker readLock(&g_lamexp_translation.lock);
+ QString qmFile = (g_lamexp_translation.files) ? g_lamexp_translation.files->value(langId.toLower(), QString()) : QString();
+ readLock.unlock();
+
+ if(!qmFile.isEmpty())
+ {
+ success = lamexp_install_translator_from_file(qmFileToPath.arg(qmFile));
+ }
+ else
+ {
+ qWarning("Translation '%s' not available!", langId.toLatin1().constData());
+ }
+ }
+
+ return success;
+}
+
+/*
+ * Install a new translator from file
+ */
+bool lamexp_install_translator_from_file(const QString &qmFile)
+{
+ QWriteLocker writeLock(&g_lamexp_currentTranslator.lock);
+ bool success = false;
+
+ if(!g_lamexp_currentTranslator.instance)
+ {
+ g_lamexp_currentTranslator.instance = new QTranslator();
+ }
+
+ if(!qmFile.isEmpty())
+ {
+ QString qmPath = QFileInfo(qmFile).canonicalFilePath();
+ QApplication::removeTranslator(g_lamexp_currentTranslator.instance);
+ if(success = g_lamexp_currentTranslator.instance->load(qmPath))
+ {
+ QApplication::installTranslator(g_lamexp_currentTranslator.instance);
+ }
+ else
+ {
+ qWarning("Failed to load translation:\n\"%s\"", qmPath.toLatin1().constData());
+ }
+ }
+ else
+ {
+ QApplication::removeTranslator(g_lamexp_currentTranslator.instance);
+ success = true;
+ }
+
+ return success;
+}
+
+/*
+ * Free all registered translations (final clean-up)
+ */
+void lamexp_clean_all_translations(void)
+{
+ QWriteLocker writeLockTranslator(&g_lamexp_currentTranslator.lock);
+
+ if(g_lamexp_currentTranslator.instance)
+ {
+ QApplication::removeTranslator(g_lamexp_currentTranslator.instance);
+ LAMEXP_DELETE(g_lamexp_currentTranslator.instance);
+ }
+
+ writeLockTranslator.unlock();
+ QWriteLocker writeLockTranslations(&g_lamexp_translation.lock);
+
+ LAMEXP_DELETE(g_lamexp_translation.files);
+ LAMEXP_DELETE(g_lamexp_translation.names);
+ LAMEXP_DELETE(g_lamexp_translation.cntry);
+ LAMEXP_DELETE(g_lamexp_translation.sysid);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+///////////////////////////////////////////////////////////////////////////////
+
+extern "C" void _lamexp_global_init_tools(void)
+{
+ LAMEXP_ZERO_MEMORY(g_lamexp_tools);
+ LAMEXP_ZERO_MEMORY(g_lamexp_currentTranslator);
+ LAMEXP_ZERO_MEMORY(g_lamexp_translation);
+}
diff --git a/src/Global_Utils.cpp b/src/Global_Utils.cpp
new file mode 100644
index 00000000..970e1cbc
--- /dev/null
+++ b/src/Global_Utils.cpp
@@ -0,0 +1,585 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2013 LoRd_MuldeR
+//
+// 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 "Global.h"
+
+//Qt includes
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//Natural sort
+#include "strnatcmp.h"
+
+//CRT includes
+#include
+#include
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL VARS
+///////////////////////////////////////////////////////////////////////////////
+
+//%TEMP% folder
+static struct
+{
+ QString *path;
+ QReadWriteLock lock;
+}
+g_lamexp_temp_folder;
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Get a random string
+ */
+QString lamexp_rand_str(const bool bLong)
+{
+ const QUuid uuid = QUuid::createUuid().toString();
+
+ const unsigned int u1 = uuid.data1;
+ const unsigned int u2 = (((unsigned int)(uuid.data2)) << 16) | ((unsigned int)(uuid.data3));
+ const unsigned int u3 = (((unsigned int)(uuid.data4[0])) << 24) | (((unsigned int)(uuid.data4[1])) << 16) | (((unsigned int)(uuid.data4[2])) << 8) | ((unsigned int)(uuid.data4[3]));
+ const unsigned int u4 = (((unsigned int)(uuid.data4[4])) << 24) | (((unsigned int)(uuid.data4[5])) << 16) | (((unsigned int)(uuid.data4[6])) << 8) | ((unsigned int)(uuid.data4[7]));
+
+ return bLong ? QString().sprintf("%08x%08x%08x%08x", u1, u2, u3, u4) : QString().sprintf("%08x%08x", (u1 ^ u2), (u3 ^ u4));
+}
+
+/*
+ * Try to initialize the folder (with *write* access)
+ */
+static QString lamexp_try_init_folder(const QString &folderPath)
+{
+ bool success = false;
+
+ const QFileInfo folderInfo(folderPath);
+ const QDir folderDir(folderInfo.absoluteFilePath());
+
+ //Create folder, if it does *not* exist yet
+ if(!folderDir.exists())
+ {
+ folderDir.mkpath(".");
+ }
+
+ //Make sure folder exists now *and* is writable
+ if(folderDir.exists())
+ {
+ QFile testFile(folderDir.absoluteFilePath(QString("~%1.tmp").arg(lamexp_rand_str())));
+ if(testFile.open(QIODevice::ReadWrite))
+ {
+ const QByteArray testData = QByteArray("Lorem ipsum dolor sit amet, consectetur, adipisci velit!");
+ if(testFile.write(testData) >= strlen(testData))
+ {
+ success = true;
+ testFile.remove();
+ }
+ testFile.close();
+ }
+ }
+
+ return (success ? folderDir.canonicalPath() : QString());
+}
+
+/*
+ * Initialize LameXP temp folder
+ */
+#define INIT_TEMP_FOLDER(OUT,TMP) do \
+{ \
+ (OUT) = lamexp_try_init_folder(QString("%1/%2").arg((TMP), lamexp_rand_str())); \
+} \
+while(0)
+
+/*
+ * Get LameXP temp folder
+ */
+const QString &lamexp_temp_folder2(void)
+{
+ QReadLocker readLock(&g_lamexp_temp_folder.lock);
+
+ //Already initialized?
+ if(g_lamexp_temp_folder.path && (!g_lamexp_temp_folder.path->isEmpty()))
+ {
+ if(QDir(*g_lamexp_temp_folder.path).exists())
+ {
+ return *g_lamexp_temp_folder.path;
+ }
+ }
+
+ //Obtain the write lock to initilaize
+ readLock.unlock();
+ QWriteLocker writeLock(&g_lamexp_temp_folder.lock);
+
+ //Still uninitilaized?
+ if(g_lamexp_temp_folder.path && (!g_lamexp_temp_folder.path->isEmpty()))
+ {
+ if(QDir(*g_lamexp_temp_folder.path).exists())
+ {
+ return *g_lamexp_temp_folder.path;
+ }
+ }
+
+ //Create the string, if not done yet
+ if(!g_lamexp_temp_folder.path)
+ {
+ g_lamexp_temp_folder.path = new QString();
+ }
+
+ g_lamexp_temp_folder.path->clear();
+
+ //Try the %TMP% or %TEMP% directory first
+ QString tempPath = lamexp_try_init_folder(QDir::temp().absolutePath());
+ if(!tempPath.isEmpty())
+ {
+ INIT_TEMP_FOLDER(*g_lamexp_temp_folder.path, tempPath);
+ }
+
+ //Otherwise create TEMP folder in %LOCALAPPDATA%
+ if(g_lamexp_temp_folder.path->isEmpty())
+ {
+ tempPath = lamexp_try_init_folder(QString("%1/Temp").arg(lamexp_known_folder(lamexp_folder_localappdata)));
+ if(!tempPath.isEmpty())
+ {
+ INIT_TEMP_FOLDER(*g_lamexp_temp_folder.path, tempPath);
+ }
+ }
+
+ //Failed to create TEMP folder?
+ if(g_lamexp_temp_folder.path->isEmpty())
+ {
+ qFatal("Temporary directory could not be initialized !!!");
+ }
+
+ return *g_lamexp_temp_folder.path;
+}
+
+/*
+ * Clear LameXP temp folder cache
+ */
+void lamexp_temp_folder_clear(void)
+{
+ QWriteLocker writeLock(&g_lamexp_temp_folder.lock);
+ LAMEXP_DELETE(g_lamexp_temp_folder.path);
+}
+
+/*
+ * Setup QPorcess object
+ */
+void lamexp_init_process(QProcess &process, const QString &wokringDir)
+{
+ //Environment variable names
+ static const char *const s_envvar_names[] =
+ {
+ "WGETRC", "SYSTEM_WGETRC", "HTTP_PROXY", "FTP_PROXY", "NO_PROXY", "GNUPGHOME", "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LANG", NULL
+ };
+
+ const QString tempDir = QDir::toNativeSeparators(lamexp_temp_folder2());
+
+ QProcessEnvironment env = process.processEnvironment();
+ if(env.isEmpty()) env = QProcessEnvironment::systemEnvironment();
+
+ //Setup TEMP directory
+ env.insert("TEMP", tempDir);
+ env.insert("TMP", tempDir);
+ env.insert("TMPDIR", tempDir);
+ env.insert("HOME", tempDir);
+ env.insert("USERPROFILE", tempDir);
+ env.insert("HOMEPATH", tempDir);
+
+ //Setup PATH variable
+ const QString path = env.value("PATH", QString());
+ env.insert("PATH", path.isEmpty() ? tempDir : QString("%1;%2").arg(tempDir, path));
+
+ //Clean a number of enviroment variables that might affect our tools
+ for(size_t i = 0; s_envvar_names[i]; i++)
+ {
+ env.remove(QString::fromLatin1(s_envvar_names[i]));
+ env.remove(QString::fromLatin1(s_envvar_names[i]).toLower());
+ }
+
+ process.setWorkingDirectory(wokringDir);
+ process.setProcessChannelMode(QProcess::MergedChannels);
+ process.setReadChannel(QProcess::StandardOutput);
+ process.setProcessEnvironment(env);
+}
+
+/*
+ * Natural Order String Comparison - the 'lessThan' helper function
+ */
+static bool lamexp_natural_string_sort_helper(const QString &str1, const QString &str2)
+{
+ return (strnatcmp(QWCHAR(str1), QWCHAR(str2)) < 0);
+}
+
+/*
+ * Natural Order String Comparison - the 'lessThan' helper function *with* case folding
+ */
+static bool lamexp_natural_string_sort_helper_fold_case(const QString &str1, const QString &str2)
+{
+ return (strnatcasecmp(QWCHAR(str1), QWCHAR(str2)) < 0);
+}
+
+/*
+ * Natural Order String Comparison - the main sorting function
+ */
+void lamexp_natural_string_sort(QStringList &list, const bool bIgnoreCase)
+{
+ qSort(list.begin(), list.end(), bIgnoreCase ? lamexp_natural_string_sort_helper_fold_case : lamexp_natural_string_sort_helper);
+}
+
+/*
+ * Remove forbidden characters from a filename
+ */
+const QString lamexp_clean_filename(const QString &str)
+{
+ QString newStr(str);
+ QRegExp rx("\"(.+)\"");
+ rx.setMinimal(true);
+
+ newStr.replace("\\", "-");
+ newStr.replace(" / ", ", ");
+ newStr.replace("/", ",");
+ newStr.replace(":", "-");
+ newStr.replace("*", "x");
+ newStr.replace("?", "");
+ newStr.replace("<", "[");
+ newStr.replace(">", "]");
+ newStr.replace("|", "!");
+ newStr.replace(rx, "`\\1´");
+ newStr.replace("\"", "'");
+
+ return newStr.simplified();
+}
+
+/*
+ * Remove forbidden characters from a file path
+ */
+const QString lamexp_clean_filepath(const QString &str)
+{
+ QStringList parts = QString(str).replace("\\", "/").split("/");
+
+ for(int i = 0; i < parts.count(); i++)
+ {
+ parts[i] = lamexp_clean_filename(parts[i]);
+ }
+
+ return parts.join("/");
+}
+
+/*
+ * Get a list of all available Qt Text Codecs
+ */
+QStringList lamexp_available_codepages(bool noAliases)
+{
+ QStringList codecList;
+
+ QList availableCodecs = QTextCodec::availableCodecs();
+ while(!availableCodecs.isEmpty())
+ {
+ QByteArray current = availableCodecs.takeFirst();
+ if(!(current.startsWith("system") || current.startsWith("System")))
+ {
+ codecList << QString::fromLatin1(current.constData(), current.size());
+ if(noAliases)
+ {
+ if(QTextCodec *currentCodec = QTextCodec::codecForName(current.constData()))
+ {
+
+ QList aliases = currentCodec->aliases();
+ while(!aliases.isEmpty()) availableCodecs.removeAll(aliases.takeFirst());
+ }
+ }
+ }
+ }
+
+ return codecList;
+}
+
+/*
+ * Robert Jenkins' 96 bit Mix Function
+ * Source: http://www.concentric.net/~Ttwang/tech/inthash.htm
+ */
+static unsigned int lamexp_mix(const unsigned int x, const unsigned int y, const unsigned int z)
+{
+ unsigned int a = x;
+ unsigned int b = y;
+ unsigned int c = z;
+
+ a=a-b; a=a-c; a=a^(c >> 13);
+ b=b-c; b=b-a; b=b^(a << 8);
+ c=c-a; c=c-b; c=c^(b >> 13);
+ a=a-b; a=a-c; a=a^(c >> 12);
+ b=b-c; b=b-a; b=b^(a << 16);
+ c=c-a; c=c-b; c=c^(b >> 5);
+ a=a-b; a=a-c; a=a^(c >> 3);
+ b=b-c; b=b-a; b=b^(a << 10);
+ c=c-a; c=c-b; c=c^(b >> 15);
+
+ return c;
+}
+
+/*
+ * Seeds the random number generator
+ * Note: Altough rand_s() doesn't need a seed, this must be called pripr to lamexp_rand(), just to to be sure!
+ */
+void lamexp_seed_rand(void)
+{
+ qsrand(lamexp_mix(clock(), time(NULL), _getpid()));
+}
+
+/*
+ * Returns a randum number
+ * Note: This function uses rand_s() if available, but falls back to qrand() otherwise
+ */
+unsigned int lamexp_rand(void)
+{
+ quint32 rnd = 0;
+
+ if(rand_s(&rnd) == 0)
+ {
+ return rnd;
+ }
+
+ for(size_t i = 0; i < sizeof(unsigned int); i++)
+ {
+ rnd = (rnd << 8) ^ qrand();
+ }
+
+ return rnd;
+}
+
+/*
+ * Make a window blink (to draw user's attention)
+ */
+void lamexp_blink_window(QWidget *poWindow, unsigned int count, unsigned int delay)
+{
+ static QMutex blinkMutex;
+
+ const double maxOpac = 1.0;
+ const double minOpac = 0.3;
+ const double delOpac = 0.1;
+
+ if(!blinkMutex.tryLock())
+ {
+ qWarning("Blinking is already in progress, skipping!");
+ return;
+ }
+
+ try
+ {
+ const int steps = static_cast(ceil(maxOpac - minOpac) / delOpac);
+ const int sleep = static_cast(floor(static_cast(delay) / static_cast(steps)));
+ const double opacity = poWindow->windowOpacity();
+
+ for(unsigned int i = 0; i < count; i++)
+ {
+ for(double x = maxOpac; x >= minOpac; x -= delOpac)
+ {
+ poWindow->setWindowOpacity(x);
+ QApplication::processEvents();
+ lamexp_sleep(sleep);
+ }
+
+ for(double x = minOpac; x <= maxOpac; x += delOpac)
+ {
+ poWindow->setWindowOpacity(x);
+ QApplication::processEvents();
+ lamexp_sleep(sleep);
+ }
+ }
+
+ poWindow->setWindowOpacity(opacity);
+ QApplication::processEvents();
+ blinkMutex.unlock();
+ }
+ catch(...)
+ {
+ blinkMutex.unlock();
+ qWarning("Exception error while blinking!");
+ }
+}
+
+/*
+ * Clean folder
+ */
+bool lamexp_clean_folder(const QString &folderPath)
+{
+ QDir tempFolder(folderPath);
+ if(tempFolder.exists())
+ {
+ QFileInfoList entryList = tempFolder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
+
+ for(int i = 0; i < entryList.count(); i++)
+ {
+ if(entryList.at(i).isDir())
+ {
+ lamexp_clean_folder(entryList.at(i).canonicalFilePath());
+ }
+ else
+ {
+ for(int j = 0; j < 3; j++)
+ {
+ if(lamexp_remove_file(entryList.at(i).canonicalFilePath()))
+ {
+ break;
+ }
+ }
+ }
+ }
+ return tempFolder.rmdir(".");
+ }
+ return true;
+}
+
+/*
+ * Computus according to H. Lichtenberg
+ */
+static bool lamexp_computus(const QDate &date)
+{
+ int X = date.year();
+ int A = X % 19;
+ int K = X / 100;
+ int M = 15 + (3*K + 3) / 4 - (8*K + 13) / 25;
+ int D = (19*A + M) % 30;
+ int S = 2 - (3*K + 3) / 4;
+ int R = D / 29 + (D / 28 - D / 29) * (A / 11);
+ int OG = 21 + D - R;
+ int SZ = 7 - (X + X / 4 + S) % 7;
+ int OE = 7 - (OG - SZ) % 7;
+ int OS = (OG + OE);
+
+ if(OS > 31)
+ {
+ return (date.month() == 4) && (date.day() == (OS - 31));
+ }
+ else
+ {
+ return (date.month() == 3) && (date.day() == OS);
+ }
+}
+
+/*
+ * Check for Thanksgiving
+ */
+static bool lamexp_thanksgiving(const QDate &date)
+{
+ int day = 0;
+
+ switch(QDate(date.year(), 11, 1).dayOfWeek())
+ {
+ case 1: day = 25; break;
+ case 2: day = 24; break;
+ case 3: day = 23; break;
+ case 4: day = 22; break;
+ case 5: day = 28; break;
+ case 6: day = 27; break;
+ case 7: day = 26; break;
+ }
+
+ return (date.month() == 11) && (date.day() == day);
+}
+
+/*
+ * Initialize app icon
+ */
+QIcon lamexp_app_icon(const QDate *date, const QTime *time)
+{
+ QDate currentDate = (date) ? QDate(*date) : QDate::currentDate();
+ QTime currentTime = (time) ? QTime(*time) : QTime::currentTime();
+
+ if(lamexp_thanksgiving(currentDate))
+ {
+ return QIcon(":/MainIcon6.png");
+ }
+ else if(((currentDate.month() == 12) && (currentDate.day() == 31) && (currentTime.hour() >= 20)) || ((currentDate.month() == 1) && (currentDate.day() == 1) && (currentTime.hour() <= 19)))
+ {
+ return QIcon(":/MainIcon5.png");
+ }
+ else if(((currentDate.month() == 10) && (currentDate.day() == 31) && (currentTime.hour() >= 12)) || ((currentDate.month() == 11) && (currentDate.day() == 1) && (currentTime.hour() <= 11)))
+ {
+ return QIcon(":/MainIcon4.png");
+ }
+ else if((currentDate.month() == 12) && (currentDate.day() >= 24) && (currentDate.day() <= 26))
+ {
+ return QIcon(":/MainIcon3.png");
+ }
+ else if(lamexp_computus(currentDate))
+ {
+ return QIcon(":/MainIcon2.png");
+ }
+ else
+ {
+ return QIcon(":/MainIcon1.png");
+ }
+}
+
+/*
+ * Broadcast event to all windows
+ */
+bool lamexp_broadcast(int eventType, bool onlyToVisible)
+{
+ if(QApplication *app = dynamic_cast(QApplication::instance()))
+ {
+ qDebug("Broadcasting %d", eventType);
+
+ bool allOk = true;
+ QEvent poEvent(static_cast(eventType));
+ QWidgetList list = app->topLevelWidgets();
+
+ while(!list.isEmpty())
+ {
+ QWidget *widget = list.takeFirst();
+ if(!onlyToVisible || widget->isVisible())
+ {
+ if(!app->sendEvent(widget, &poEvent))
+ {
+ allOk = false;
+ }
+ }
+ }
+
+ qDebug("Broadcast %d done (%s)", eventType, (allOk ? "OK" : "Stopped"));
+ return allOk;
+ }
+ else
+ {
+ qWarning("Broadcast failed, could not get QApplication instance!");
+ return false;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+///////////////////////////////////////////////////////////////////////////////
+
+extern "C" void _lamexp_global_init_utils(void)
+{
+ LAMEXP_ZERO_MEMORY(g_lamexp_temp_folder);
+}
diff --git a/src/Global_Version.cpp b/src/Global_Version.cpp
new file mode 100644
index 00000000..f5aeaf88
--- /dev/null
+++ b/src/Global_Version.cpp
@@ -0,0 +1,327 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2013 LoRd_MuldeR
+//
+// 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 "Global.h"
+
+//LameXP includes
+#define LAMEXP_INC_CONFIG
+#include "Resource.h"
+#include "Config.h"
+
+//Qt includes
+#include
+#include
+#include
+#include
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL VARS
+///////////////////////////////////////////////////////////////////////////////
+
+//Build version
+static const struct
+{
+ unsigned int ver_major;
+ unsigned int ver_minor;
+ unsigned int ver_build;
+ unsigned int ver_confg;
+ char *ver_release_name;
+}
+g_lamexp_version =
+{
+ VER_LAMEXP_MAJOR,
+ (10 * VER_LAMEXP_MINOR_HI) + VER_LAMEXP_MINOR_LO,
+ VER_LAMEXP_BUILD,
+ VER_LAMEXP_CONFG,
+ VER_LAMEXP_RNAME,
+};
+
+//Portable Mode
+static struct
+{
+ bool bInitialized;
+ bool bPortableModeEnabled;
+ QReadWriteLock lock;
+}
+g_lamexp_portable;
+
+//Build date
+static QDate g_lamexp_version_date;
+static const char *g_lamexp_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+static const char *g_lamexp_version_raw_date = __DATE__;
+static const char *g_lamexp_version_raw_time = __TIME__;
+
+//Official web-site URL
+static const char *g_lamexp_website_url = "http://lamexp.sourceforge.net/";
+static const char *g_lamexp_support_url = "http://forum.doom9.org/showthread.php?t=157726";
+static const char *g_lamexp_mulders_url = "http://muldersoft.com/";
+
+//Tool versions (expected versions!)
+static const unsigned int g_lamexp_toolver_neroaac = VER_LAMEXP_TOOL_NEROAAC;
+static const unsigned int g_lamexp_toolver_fhgaacenc = VER_LAMEXP_TOOL_FHGAACENC;
+static const unsigned int g_lamexp_toolver_qaacenc = VER_LAMEXP_TOOL_QAAC;
+static const unsigned int g_lamexp_toolver_coreaudio = VER_LAMEXP_TOOL_COREAUDIO;
+
+///////////////////////////////////////////////////////////////////////////////
+// COMPILER INFO
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Disclaimer: Parts of the following code were borrowed from MPC-HC project: http://mpc-hc.sf.net/
+ */
+
+//Compiler detection
+#if defined(__INTEL_COMPILER)
+ #if (__INTEL_COMPILER >= 1300)
+ static const char *g_lamexp_version_compiler = "ICL 13." LAMEXP_MAKE_STR(__INTEL_COMPILER_BUILD_DATE);
+ #elif (__INTEL_COMPILER >= 1200)
+ static const char *g_lamexp_version_compiler = "ICL 12." LAMEXP_MAKE_STR(__INTEL_COMPILER_BUILD_DATE);
+ #elif (__INTEL_COMPILER >= 1100)
+ static const char *g_lamexp_version_compiler = "ICL 11.x";
+ #elif (__INTEL_COMPILER >= 1000)
+ static const char *g_lamexp_version_compiler = "ICL 10.x";
+ #else
+ #error Compiler is not supported!
+ #endif
+#elif defined(_MSC_VER)
+ #if (_MSC_VER == 1800)
+ #if (_MSC_FULL_VER < 180021005)
+ static const char *g_lamexp_version_compiler = "MSVC 2013-Beta";
+ #elif (_MSC_FULL_VER == 180021005)
+ static const char *g_lamexp_version_compiler = "MSVC 2013";
+ #else
+ #error Compiler version is not supported yet!
+ #endif
+ #elif (_MSC_VER == 1700)
+ #if (_MSC_FULL_VER < 170050727)
+ static const char *g_lamexp_version_compiler = "MSVC 2012-Beta";
+ #elif (_MSC_FULL_VER < 170051020)
+ static const char *g_lamexp_version_compiler = "MSVC 2012";
+ #elif (_MSC_FULL_VER < 170051106)
+ static const char *g_lamexp_version_compiler = "MSVC 2012.1-CTP";
+ #elif (_MSC_FULL_VER < 170060315)
+ static const char *g_lamexp_version_compiler = "MSVC 2012.1";
+ #elif (_MSC_FULL_VER < 170060610)
+ static const char *g_lamexp_version_compiler = "MSVC 2012.2";
+ #elif (_MSC_FULL_VER == 170060610)
+ static const char *g_lamexp_version_compiler = "MSVC 2012.3";
+ #else
+ #error Compiler version is not supported yet!
+ #endif
+ #elif (_MSC_VER == 1600)
+ #if (_MSC_FULL_VER < 160040219)
+ static const char *g_lamexp_version_compiler = "MSVC 2010";
+ #elif (_MSC_FULL_VER == 160040219)
+ static const char *g_lamexp_version_compiler = "MSVC 2010-SP1";
+ #else
+ #error Compiler version is not supported yet!
+ #endif
+ #elif (_MSC_VER == 1500)
+ #if (_MSC_FULL_VER >= 150030729)
+ static const char *g_lamexp_version_compiler = "MSVC 2008-SP1";
+ #else
+ static const char *g_lamexp_version_compiler = "MSVC 2008";
+ #endif
+ #else
+ #error Compiler is not supported!
+ #endif
+
+ // Note: /arch:SSE and /arch:SSE2 are only available for the x86 platform
+ #if !defined(_M_X64) && defined(_M_IX86_FP)
+ #if (_M_IX86_FP == 1)
+ LAMEXP_COMPILER_WARNING("SSE instruction set is enabled!")
+ #elif (_M_IX86_FP == 2)
+ LAMEXP_COMPILER_WARNING("SSE2 (or higher) instruction set is enabled!")
+ #endif
+ #endif
+#else
+ #error Compiler is not supported!
+#endif
+
+//Architecture detection
+#if defined(_M_X64)
+ static const char *g_lamexp_version_arch = "x64";
+#elif defined(_M_IX86)
+ static const char *g_lamexp_version_arch = "x86";
+#else
+ #error Architecture is not supported!
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// GLOBAL FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Version getters
+ */
+unsigned int lamexp_version_major(void) { return g_lamexp_version.ver_major; }
+unsigned int lamexp_version_minor(void) { return g_lamexp_version.ver_minor; }
+unsigned int lamexp_version_build(void) { return g_lamexp_version.ver_build; }
+unsigned int lamexp_version_confg(void) { return g_lamexp_version.ver_confg; }
+const char *lamexp_version_release(void) { return g_lamexp_version.ver_release_name; }
+const char *lamexp_version_time(void) { return g_lamexp_version_raw_time; }
+const char *lamexp_version_compiler(void) { return g_lamexp_version_compiler; }
+const char *lamexp_version_arch(void) { return g_lamexp_version_arch; }
+unsigned int lamexp_toolver_neroaac(void) { return g_lamexp_toolver_neroaac; }
+unsigned int lamexp_toolver_fhgaacenc(void) { return g_lamexp_toolver_fhgaacenc; }
+unsigned int lamexp_toolver_qaacenc(void) { return g_lamexp_toolver_qaacenc; }
+unsigned int lamexp_toolver_coreaudio(void) { return g_lamexp_toolver_coreaudio; }
+
+/*
+ * URL getters
+ */
+const char *lamexp_website_url(void) { return g_lamexp_website_url; }
+const char *lamexp_mulders_url(void) { return g_lamexp_mulders_url; }
+const char *lamexp_support_url(void) { return g_lamexp_support_url; }
+
+/*
+ * Check for Demo (pre-release) version
+ */
+bool lamexp_version_demo(void)
+{
+ char buffer[128];
+ bool releaseVersion = false;
+ if(!strncpy_s(buffer, 128, g_lamexp_version.ver_release_name, _TRUNCATE))
+ {
+ char *context, *prefix = strtok_s(buffer, "-,; ", &context);
+ if(prefix)
+ {
+ releaseVersion = (!_stricmp(prefix, "Final")) || (!_stricmp(prefix, "Hotfix"));
+ }
+ }
+ return (!releaseVersion);
+}
+
+/*
+ * Calculate expiration date
+ */
+QDate lamexp_version_expires(void)
+{
+ return lamexp_version_date().addDays(LAMEXP_DEBUG ? 7 : 30);
+}
+
+/*
+ * Convert month string to integer value
+ */
+static int lamexp_month2int(const char *str)
+{
+ int ret = 0;
+
+ for(int j = 0; j < 12; j++)
+ {
+ if(!_strcmpi(str, g_lamexp_months[j]))
+ {
+ ret = j+1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Get build date date
+ */
+const QDate &lamexp_version_date(void)
+{
+ //Format of __DATE__ is defined as: "MMM DD YYYY"
+ if(!g_lamexp_version_date.isValid())
+ {
+ int date[3] = {0, 0, 0};
+ char temp_m[4], temp_d[3], temp_y[5];
+
+ temp_m[0] = g_lamexp_version_raw_date[0x0];
+ temp_m[1] = g_lamexp_version_raw_date[0x1];
+ temp_m[2] = g_lamexp_version_raw_date[0x2];
+ temp_m[3] = 0x00;
+
+ temp_d[0] = g_lamexp_version_raw_date[0x4];
+ temp_d[1] = g_lamexp_version_raw_date[0x5];
+ temp_d[2] = 0x00;
+
+ temp_y[0] = g_lamexp_version_raw_date[0x7];
+ temp_y[1] = g_lamexp_version_raw_date[0x8];
+ temp_y[2] = g_lamexp_version_raw_date[0x9];
+ temp_y[3] = g_lamexp_version_raw_date[0xA];
+ temp_y[4] = 0x00;
+
+ date[0] = atoi(temp_y);
+ date[1] = lamexp_month2int(temp_m);
+ date[2] = atoi(temp_d);
+
+ if((date[0] > 0) && (date[1] > 0) && (date[2] > 0))
+ {
+
+ g_lamexp_version_date = QDate(date[0], date[1], date[2]);
+ }
+ else
+ {
+ THROW("Internal error: Date format could not be recognized!");
+ }
+ }
+
+ return g_lamexp_version_date;
+}
+
+/*
+ * Check for LameXP "portable" mode
+ */
+bool lamexp_portable_mode(void)
+{
+ QReadLocker readLock(&g_lamexp_portable.lock);
+
+ if(g_lamexp_portable.bInitialized)
+ {
+ return g_lamexp_portable.bPortableModeEnabled;
+ }
+
+ readLock.unlock();
+ QWriteLocker writeLock(&g_lamexp_portable.lock);
+
+ if(!g_lamexp_portable.bInitialized)
+ {
+ if(VER_LAMEXP_PORTABLE_EDITION)
+ {
+ qWarning("LameXP portable edition!\n");
+ g_lamexp_portable.bPortableModeEnabled = true;
+ }
+ else
+ {
+ QString baseName = QFileInfo(QApplication::applicationFilePath()).completeBaseName();
+ int idx1 = baseName.indexOf("lamexp", 0, Qt::CaseInsensitive);
+ int idx2 = baseName.lastIndexOf("portable", -1, Qt::CaseInsensitive);
+ g_lamexp_portable.bPortableModeEnabled = (idx1 >= 0) && (idx2 >= 0) && (idx1 < idx2);
+ }
+ g_lamexp_portable.bInitialized = true;
+ }
+
+ return g_lamexp_portable.bPortableModeEnabled;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+///////////////////////////////////////////////////////////////////////////////
+
+extern "C" void _lamexp_global_init_versn(void)
+{
+ LAMEXP_ZERO_MEMORY(g_lamexp_portable);
+}
diff --git a/src/Global.cpp b/src/Global_Win32.cpp
similarity index 56%
rename from src/Global.cpp
rename to src/Global_Win32.cpp
index 99415c8a..cfd6c250 100644
--- a/src/Global.cpp
+++ b/src/Global_Win32.cpp
@@ -22,6 +22,12 @@
#include "Global.h"
+//Target version
+#include "Targetver.h"
+
+//Visual Leaks Detector
+#include
+
//Windows includes
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
@@ -29,63 +35,48 @@
#include
#include
#include
+#include
+#include
+#include
//Qt includes
#include
-#include
-#include
-#include
-#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
//LameXP includes
#define LAMEXP_INC_CONFIG
#include "Resource.h"
#include "Config.h"
-#include "LockedFile.h"
-#include "strnatcmp.h"
//CRT includes
+#include
#include
#include
#include
#include
#include
-#include
-#include
+#include
+#include
#include
-//Shell API
-#include
-
-//COM includes
-#include
-#include
-
-//Process API
-#include
-
//Initialize static Qt plugins
#ifdef QT_NODLL
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
@@ -97,9 +88,10 @@ Q_IMPORT_PLUGIN(QICOPlugin)
#endif
#endif
-#define LAMEXP_ZERO_MEMORY(X) SecureZeroMemory(&X, sizeof(X))
+///////////////////////////////////////////////////////////////////////////////
+// HELPER MACROS
+///////////////////////////////////////////////////////////////////////////////
-//Helper macros
#define _LAMEXP_MAKE_STR(STR) #STR
#define LAMEXP_MAKE_STR(STR) _LAMEXP_MAKE_STR(STR)
@@ -125,71 +117,13 @@ while(0)
} \
while(0)
-///////////////////////////////////////////////////////////////////////////////
-// TYPES
-///////////////////////////////////////////////////////////////////////////////
-
-static const size_t g_lamexp_ipc_slots = 128;
-
-typedef struct
-{
- unsigned int command;
- unsigned int reserved_1;
- unsigned int reserved_2;
- char parameter[4096];
-}
-lamexp_ipc_data_t;
-
-typedef struct
-{
- unsigned int pos_write;
- unsigned int pos_read;
- lamexp_ipc_data_t data[g_lamexp_ipc_slots];
-}
-lamexp_ipc_t;
-
///////////////////////////////////////////////////////////////////////////////
// GLOBAL VARS
///////////////////////////////////////////////////////////////////////////////
-//Build version
-static const struct
-{
- unsigned int ver_major;
- unsigned int ver_minor;
- unsigned int ver_build;
- unsigned int ver_confg;
- char *ver_release_name;
-}
-g_lamexp_version =
-{
- VER_LAMEXP_MAJOR,
- (10 * VER_LAMEXP_MINOR_HI) + VER_LAMEXP_MINOR_LO,
- VER_LAMEXP_BUILD,
- VER_LAMEXP_CONFG,
- VER_LAMEXP_RNAME,
-};
-
-//Build date
-static QDate g_lamexp_version_date;
-static const char *g_lamexp_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-static const char *g_lamexp_version_raw_date = __DATE__;
-static const char *g_lamexp_version_raw_time = __TIME__;
-
//Console attached flag
static bool g_lamexp_console_attached = false;
-//Official web-site URL
-static const char *g_lamexp_website_url = "http://lamexp.sourceforge.net/";
-static const char *g_lamexp_support_url = "http://forum.doom9.org/showthread.php?t=157726";
-static const char *g_lamexp_mulders_url = "http://muldersoft.com/";
-
-//Tool versions (expected versions!)
-static const unsigned int g_lamexp_toolver_neroaac = VER_LAMEXP_TOOL_NEROAAC;
-static const unsigned int g_lamexp_toolver_fhgaacenc = VER_LAMEXP_TOOL_FHGAACENC;
-static const unsigned int g_lamexp_toolver_qaacenc = VER_LAMEXP_TOOL_QAAC;
-static const unsigned int g_lamexp_toolver_coreaudio = VER_LAMEXP_TOOL_COREAUDIO;
-
//Special folders
static struct
{
@@ -198,43 +132,6 @@ static struct
}
g_lamexp_known_folder;
-//%TEMP% folder
-static struct
-{
- QString *path;
- QReadWriteLock lock;
-}
-g_lamexp_temp_folder;
-
-//Tools
-static struct
-{
- QMap *registry;
- QMap *versions;
- QMap *tags;
- QReadWriteLock lock;
-}
-g_lamexp_tools;
-
-//Languages
-static struct
-{
- QMap *files;
- QMap *names;
- QMap *sysid;
- QMap *cntry;
- QReadWriteLock lock;
-}
-g_lamexp_translation;
-
-//Translator
-static struct
-{
- QTranslator *instance;
- QReadWriteLock lock;
-}
-g_lamexp_currentTranslator;
-
//CLI Arguments
static struct
{
@@ -252,14 +149,14 @@ static struct
}
g_lamexp_os_version;
-//Portable Mode
+//Wine detection
static struct
{
bool bInitialized;
- bool bPortableModeEnabled;
+ bool bIsWine;
QReadWriteLock lock;
}
-g_lamexp_portable;
+g_lamexp_wine;
//Win32 Theme support
static struct
@@ -270,34 +167,6 @@ static struct
}
g_lamexp_themes_enabled;
-//Shared memory
-static const struct
-{
- char *sharedmem;
- char *semaphore_read;
- char *semaphore_read_mutex;
- char *semaphore_write;
- char *semaphore_write_mutex;
-}
-g_lamexp_ipc_uuid =
-{
- "{21A68A42-6923-43bb-9CF6-64BF151942EE}",
- "{7A605549-F58C-4d78-B4E5-06EFC34F405B}",
- "{60AA8D04-F6B8-497d-81EB-0F600F4A65B5}",
- "{726061D5-1615-4B82-871C-75FD93458E46}",
- "{1A616023-AA6A-4519-8AF3-F7736E899977}"
-};
-static struct
-{
- QSharedMemory *sharedmem;
- QSystemSemaphore *semaphore_read;
- QSystemSemaphore *semaphore_read_mutex;
- QSystemSemaphore *semaphore_write;
- QSystemSemaphore *semaphore_write_mutex;
- QReadWriteLock lock;
-}
-g_lamexp_ipc_ptr;
-
//Image formats
static const char *g_lamexp_imageformats[] = {"bmp", "png", "jpg", "gif", "ico", "xpm", NULL}; //"svg"
@@ -326,207 +195,13 @@ const lamexp_os_version_t lamexp_winver_win81 = {6,3};
//GURU MEDITATION
static const char *GURU_MEDITATION = "\n\nGURU MEDITATION !!!\n\n";
-///////////////////////////////////////////////////////////////////////////////
-// COMPILER INFO
-///////////////////////////////////////////////////////////////////////////////
-
-/*
- * Disclaimer: Parts of the following code were borrowed from MPC-HC project: http://mpc-hc.sf.net/
- */
-
-//Compiler detection
-#if defined(__INTEL_COMPILER)
- #if (__INTEL_COMPILER >= 1300)
- static const char *g_lamexp_version_compiler = "ICL 13." LAMEXP_MAKE_STR(__INTEL_COMPILER_BUILD_DATE);
- #elif (__INTEL_COMPILER >= 1200)
- static const char *g_lamexp_version_compiler = "ICL 12." LAMEXP_MAKE_STR(__INTEL_COMPILER_BUILD_DATE);
- #elif (__INTEL_COMPILER >= 1100)
- static const char *g_lamexp_version_compiler = "ICL 11.x";
- #elif (__INTEL_COMPILER >= 1000)
- static const char *g_lamexp_version_compiler = "ICL 10.x";
- #else
- #error Compiler is not supported!
- #endif
-#elif defined(_MSC_VER)
- #if (_MSC_VER == 1800)
- #if (_MSC_FULL_VER < 180021005)
- static const char *g_lamexp_version_compiler = "MSVC 2013-Beta";
- #elif (_MSC_FULL_VER == 180021005)
- static const char *g_lamexp_version_compiler = "MSVC 2013";
- #else
- #error Compiler version is not supported yet!
- #endif
- #elif (_MSC_VER == 1700)
- #if (_MSC_FULL_VER < 170050727)
- static const char *g_lamexp_version_compiler = "MSVC 2012-Beta";
- #elif (_MSC_FULL_VER < 170051020)
- static const char *g_lamexp_version_compiler = "MSVC 2012";
- #elif (_MSC_FULL_VER < 170051106)
- static const char *g_lamexp_version_compiler = "MSVC 2012.1-CTP";
- #elif (_MSC_FULL_VER < 170060315)
- static const char *g_lamexp_version_compiler = "MSVC 2012.1";
- #elif (_MSC_FULL_VER < 170060610)
- static const char *g_lamexp_version_compiler = "MSVC 2012.2";
- #elif (_MSC_FULL_VER == 170060610)
- static const char *g_lamexp_version_compiler = "MSVC 2012.3";
- #else
- #error Compiler version is not supported yet!
- #endif
- #elif (_MSC_VER == 1600)
- #if (_MSC_FULL_VER < 160040219)
- static const char *g_lamexp_version_compiler = "MSVC 2010";
- #elif (_MSC_FULL_VER == 160040219)
- static const char *g_lamexp_version_compiler = "MSVC 2010-SP1";
- #else
- #error Compiler version is not supported yet!
- #endif
- #elif (_MSC_VER == 1500)
- #if (_MSC_FULL_VER >= 150030729)
- static const char *g_lamexp_version_compiler = "MSVC 2008-SP1";
- #else
- static const char *g_lamexp_version_compiler = "MSVC 2008";
- #endif
- #else
- #error Compiler is not supported!
- #endif
-
- // Note: /arch:SSE and /arch:SSE2 are only available for the x86 platform
- #if !defined(_M_X64) && defined(_M_IX86_FP)
- #if (_M_IX86_FP == 1)
- LAMEXP_COMPILER_WARNING("SSE instruction set is enabled!")
- #elif (_M_IX86_FP == 2)
- LAMEXP_COMPILER_WARNING("SSE2 (or higher) instruction set is enabled!")
- #endif
- #endif
-#else
- #error Compiler is not supported!
-#endif
-
-//Architecture detection
-#if defined(_M_X64)
- static const char *g_lamexp_version_arch = "x64";
-#elif defined(_M_IX86)
- static const char *g_lamexp_version_arch = "x86";
-#else
- #error Architecture is not supported!
-#endif
-
///////////////////////////////////////////////////////////////////////////////
// GLOBAL FUNCTIONS
///////////////////////////////////////////////////////////////////////////////
/*
- * Version getters
+ * Verify a specific Windows version
*/
-unsigned int lamexp_version_major(void) { return g_lamexp_version.ver_major; }
-unsigned int lamexp_version_minor(void) { return g_lamexp_version.ver_minor; }
-unsigned int lamexp_version_build(void) { return g_lamexp_version.ver_build; }
-unsigned int lamexp_version_confg(void) { return g_lamexp_version.ver_confg; }
-const char *lamexp_version_release(void) { return g_lamexp_version.ver_release_name; }
-const char *lamexp_version_time(void) { return g_lamexp_version_raw_time; }
-const char *lamexp_version_compiler(void) { return g_lamexp_version_compiler; }
-const char *lamexp_version_arch(void) { return g_lamexp_version_arch; }
-unsigned int lamexp_toolver_neroaac(void) { return g_lamexp_toolver_neroaac; }
-unsigned int lamexp_toolver_fhgaacenc(void) { return g_lamexp_toolver_fhgaacenc; }
-unsigned int lamexp_toolver_qaacenc(void) { return g_lamexp_toolver_qaacenc; }
-unsigned int lamexp_toolver_coreaudio(void) { return g_lamexp_toolver_coreaudio; }
-
-/*
- * URL getters
- */
-const char *lamexp_website_url(void) { return g_lamexp_website_url; }
-const char *lamexp_mulders_url(void) { return g_lamexp_mulders_url; }
-const char *lamexp_support_url(void) { return g_lamexp_support_url; }
-
-/*
- * Check for Demo (pre-release) version
- */
-bool lamexp_version_demo(void)
-{
- char buffer[128];
- bool releaseVersion = false;
- if(!strncpy_s(buffer, 128, g_lamexp_version.ver_release_name, _TRUNCATE))
- {
- char *context, *prefix = strtok_s(buffer, "-,; ", &context);
- if(prefix)
- {
- releaseVersion = (!_stricmp(prefix, "Final")) || (!_stricmp(prefix, "Hotfix"));
- }
- }
- return (!releaseVersion);
-}
-
-/*
- * Calculate expiration date
- */
-QDate lamexp_version_expires(void)
-{
- return lamexp_version_date().addDays(LAMEXP_DEBUG ? 7 : 30);
-}
-
-/*
- * Convert month string to integer value
- */
-static int lamexp_month2int(const char *str)
-{
- int ret = 0;
-
- for(int j = 0; j < 12; j++)
- {
- if(!_strcmpi(str, g_lamexp_months[j]))
- {
- ret = j+1;
- break;
- }
- }
-
- return ret;
-}
-
-/*
- * Get build date date
- */
-const QDate &lamexp_version_date(void)
-{
- //Format of __DATE__ is defined as: "MMM DD YYYY"
- if(!g_lamexp_version_date.isValid())
- {
- int date[3] = {0, 0, 0};
- char temp_m[4], temp_d[3], temp_y[5];
-
- temp_m[0] = g_lamexp_version_raw_date[0x0];
- temp_m[1] = g_lamexp_version_raw_date[0x1];
- temp_m[2] = g_lamexp_version_raw_date[0x2];
- temp_m[3] = 0x00;
-
- temp_d[0] = g_lamexp_version_raw_date[0x4];
- temp_d[1] = g_lamexp_version_raw_date[0x5];
- temp_d[2] = 0x00;
-
- temp_y[0] = g_lamexp_version_raw_date[0x7];
- temp_y[1] = g_lamexp_version_raw_date[0x8];
- temp_y[2] = g_lamexp_version_raw_date[0x9];
- temp_y[3] = g_lamexp_version_raw_date[0xA];
- temp_y[4] = 0x00;
-
- date[0] = atoi(temp_y);
- date[1] = lamexp_month2int(temp_m);
- date[2] = atoi(temp_d);
-
- if((date[0] > 0) && (date[1] > 0) && (date[2] > 0))
- {
-
- g_lamexp_version_date = QDate(date[0], date[1], date[2]);
- }
- else
- {
- THROW("Internal error: Date format could not be recognized!");
- }
- }
-
- return g_lamexp_version_date;
-}
-
static bool lamexp_verify_os_version(const DWORD major, const DWORD minor)
{
OSVERSIONINFOEXW osvi;
@@ -662,31 +337,31 @@ const lamexp_os_version_t &lamexp_get_os_version(void)
*/
bool lamexp_detect_wine(void)
{
- static bool isWine = false;
- static bool isWine_initialized = false;
+ QReadLocker readLock(&g_lamexp_wine.lock);
- if(!isWine_initialized)
+ //Already initialized?
+ if(g_lamexp_wine.bInitialized)
{
+ return g_lamexp_wine.bIsWine;
+ }
+
+ readLock.unlock();
+ QWriteLocker writeLock(&g_lamexp_wine.lock);
+
+ if(!g_lamexp_wine.bInitialized)
+ {
+ g_lamexp_wine.bIsWine = false;
QLibrary ntdll("ntdll.dll");
if(ntdll.load())
{
- if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) isWine = true;
- if(ntdll.resolve("wine_get_version") != NULL) isWine = true;
+ if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) g_lamexp_wine.bIsWine = true;
+ if(ntdll.resolve("wine_get_version") != NULL) g_lamexp_wine.bIsWine = true;
ntdll.unload();
}
- isWine_initialized = true;
+ g_lamexp_wine.bInitialized = true;
}
- return isWine;
-}
-
-/*
- * Global exception handler
- */
-LONG WINAPI lamexp_exception_handler(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
-{
- lamexp_fatal_exit(L"Unhandeled exception handler invoked, application will exit!");
- return LONG_MAX;
+ return g_lamexp_wine.bIsWine;
}
/*
@@ -865,6 +540,27 @@ void lamexp_message_handler(QtMsgType type, const char *msg)
}
}
+
+/*
+ * Global exception handler
+ */
+static LONG WINAPI lamexp_exception_handler(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
+{
+ lamexp_fatal_exit(L"Unhandeled exception handler invoked, application will exit!");
+ return LONG_MAX;
+}
+
+/*
+ * Initialize error handlers
+ */
+void lamexp_init_error_handlers(void)
+{
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ SetUnhandledExceptionFilter(lamexp_exception_handler);
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
+ _set_invalid_parameter_handler(lamexp_invalid_param_handler);
+}
+
/*
* Initialize the console
*/
@@ -1109,123 +805,6 @@ static HANDLE lamexp_debug_thread_init()
return (HANDLE)(h^0xdeadbeef);
}
-/*
- * Computus according to H. Lichtenberg
- */
-static bool lamexp_computus(const QDate &date)
-{
- int X = date.year();
- int A = X % 19;
- int K = X / 100;
- int M = 15 + (3*K + 3) / 4 - (8*K + 13) / 25;
- int D = (19*A + M) % 30;
- int S = 2 - (3*K + 3) / 4;
- int R = D / 29 + (D / 28 - D / 29) * (A / 11);
- int OG = 21 + D - R;
- int SZ = 7 - (X + X / 4 + S) % 7;
- int OE = 7 - (OG - SZ) % 7;
- int OS = (OG + OE);
-
- if(OS > 31)
- {
- return (date.month() == 4) && (date.day() == (OS - 31));
- }
- else
- {
- return (date.month() == 3) && (date.day() == OS);
- }
-}
-
-/*
- * Check for Thanksgiving
- */
-static bool lamexp_thanksgiving(const QDate &date)
-{
- int day = 0;
-
- switch(QDate(date.year(), 11, 1).dayOfWeek())
- {
- case 1: day = 25; break;
- case 2: day = 24; break;
- case 3: day = 23; break;
- case 4: day = 22; break;
- case 5: day = 28; break;
- case 6: day = 27; break;
- case 7: day = 26; break;
- }
-
- return (date.month() == 11) && (date.day() == day);
-}
-
-/*
- * Initialize app icon
- */
-QIcon lamexp_app_icon(const QDate *date, const QTime *time)
-{
- QDate currentDate = (date) ? QDate(*date) : QDate::currentDate();
- QTime currentTime = (time) ? QTime(*time) : QTime::currentTime();
-
- if(lamexp_thanksgiving(currentDate))
- {
- return QIcon(":/MainIcon6.png");
- }
- else if(((currentDate.month() == 12) && (currentDate.day() == 31) && (currentTime.hour() >= 20)) || ((currentDate.month() == 1) && (currentDate.day() == 1) && (currentTime.hour() <= 19)))
- {
- return QIcon(":/MainIcon5.png");
- }
- else if(((currentDate.month() == 10) && (currentDate.day() == 31) && (currentTime.hour() >= 12)) || ((currentDate.month() == 11) && (currentDate.day() == 1) && (currentTime.hour() <= 11)))
- {
- return QIcon(":/MainIcon4.png");
- }
- else if((currentDate.month() == 12) && (currentDate.day() >= 24) && (currentDate.day() <= 26))
- {
- return QIcon(":/MainIcon3.png");
- }
- else if(lamexp_computus(currentDate))
- {
- return QIcon(":/MainIcon2.png");
- }
- else
- {
- return QIcon(":/MainIcon1.png");
- }
-}
-
-/*
- * Broadcast event to all windows
- */
-static bool lamexp_broadcast(int eventType, bool onlyToVisible)
-{
- if(QApplication *app = dynamic_cast(QApplication::instance()))
- {
- qDebug("Broadcasting %d", eventType);
-
- bool allOk = true;
- QEvent poEvent(static_cast(eventType));
- QWidgetList list = app->topLevelWidgets();
-
- while(!list.isEmpty())
- {
- QWidget *widget = list.takeFirst();
- if(!onlyToVisible || widget->isVisible())
- {
- if(!app->sendEvent(widget, &poEvent))
- {
- allOk = false;
- }
- }
- }
-
- qDebug("Broadcast %d done (%s)", eventType, (allOk ? "OK" : "Stopped"));
- return allOk;
- }
- else
- {
- qWarning("Broadcast failed, could not get QApplication instance!");
- return false;
- }
-}
-
/*
* Qt event filter
*/
@@ -1452,13 +1031,8 @@ bool lamexp_init_qt(int argc, char* argv[])
}
}
- //Add default translations
- QWriteLocker writeLockTranslations(&g_lamexp_translation.lock);
- if(!g_lamexp_translation.files) g_lamexp_translation.files = new QMap();
- if(!g_lamexp_translation.names) g_lamexp_translation.names = new QMap();
- g_lamexp_translation.files->insert(LAMEXP_DEFAULT_LANGID, "");
- g_lamexp_translation.names->insert(LAMEXP_DEFAULT_LANGID, "English");
- writeLockTranslations.unlock();
+ //Add the default translations
+ lamexp_translation_init();
//Check for process elevation
if((!lamexp_check_elevation()) && (!lamexp_detect_wine()))
@@ -1481,7 +1055,8 @@ bool lamexp_init_qt(int argc, char* argv[])
if(kernel32.load())
{
SetConsoleIconFun SetConsoleIconPtr = (SetConsoleIconFun) kernel32.resolve("SetConsoleIcon");
- if(SetConsoleIconPtr != NULL) SetConsoleIconPtr(QIcon(":/icons/sound.png").pixmap(16, 16).toWinHICON());
+ QPixmap pixmap = QIcon(":/icons/sound.png").pixmap(16, 16);
+ if((SetConsoleIconPtr != NULL) && (!pixmap.isNull())) SetConsoleIconPtr(pixmap.toWinHICON());
kernel32.unload();
}
}
@@ -1492,611 +1067,6 @@ bool lamexp_init_qt(int argc, char* argv[])
return true;
}
-/*
- * Initialize IPC
- */
-int lamexp_init_ipc(void)
-{
- QWriteLocker writeLock(&g_lamexp_ipc_ptr.lock);
-
- if(g_lamexp_ipc_ptr.sharedmem && g_lamexp_ipc_ptr.semaphore_read && g_lamexp_ipc_ptr.semaphore_write && g_lamexp_ipc_ptr.semaphore_read_mutex && g_lamexp_ipc_ptr.semaphore_write_mutex)
- {
- return 0;
- }
-
- g_lamexp_ipc_ptr.semaphore_read = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_read), 0);
- g_lamexp_ipc_ptr.semaphore_write = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_write), 0);
- g_lamexp_ipc_ptr.semaphore_read_mutex = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_read_mutex), 0);
- g_lamexp_ipc_ptr.semaphore_write_mutex = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_write_mutex), 0);
-
- if(g_lamexp_ipc_ptr.semaphore_read->error() != QSystemSemaphore::NoError)
- {
- QString errorMessage = g_lamexp_ipc_ptr.semaphore_read->errorString();
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
- qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage));
- return -1;
- }
- if(g_lamexp_ipc_ptr.semaphore_write->error() != QSystemSemaphore::NoError)
- {
- QString errorMessage = g_lamexp_ipc_ptr.semaphore_write->errorString();
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
- qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage));
- return -1;
- }
- if(g_lamexp_ipc_ptr.semaphore_read_mutex->error() != QSystemSemaphore::NoError)
- {
- QString errorMessage = g_lamexp_ipc_ptr.semaphore_read_mutex->errorString();
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
- qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage));
- return -1;
- }
- if(g_lamexp_ipc_ptr.semaphore_write_mutex->error() != QSystemSemaphore::NoError)
- {
- QString errorMessage = g_lamexp_ipc_ptr.semaphore_write_mutex->errorString();
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
- qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage));
- return -1;
- }
-
- g_lamexp_ipc_ptr.sharedmem = new QSharedMemory(QString(g_lamexp_ipc_uuid.sharedmem), NULL);
-
- if(!g_lamexp_ipc_ptr.sharedmem->create(sizeof(lamexp_ipc_t)))
- {
- if(g_lamexp_ipc_ptr.sharedmem->error() == QSharedMemory::AlreadyExists)
- {
- g_lamexp_ipc_ptr.sharedmem->attach();
- if(g_lamexp_ipc_ptr.sharedmem->error() == QSharedMemory::NoError)
- {
- return 1;
- }
- else
- {
- QString errorMessage = g_lamexp_ipc_ptr.sharedmem->errorString();
- LAMEXP_DELETE(g_lamexp_ipc_ptr.sharedmem);
- qFatal("Failed to attach to shared memory: %s", QUTF8(errorMessage));
- return -1;
- }
- }
- else
- {
- QString errorMessage = g_lamexp_ipc_ptr.sharedmem->errorString();
- LAMEXP_DELETE(g_lamexp_ipc_ptr.sharedmem);
- qFatal("Failed to create shared memory: %s", QUTF8(errorMessage));
- return -1;
- }
- }
-
- memset(g_lamexp_ipc_ptr.sharedmem->data(), 0, sizeof(lamexp_ipc_t));
- g_lamexp_ipc_ptr.semaphore_write->release(g_lamexp_ipc_slots);
- g_lamexp_ipc_ptr.semaphore_read_mutex->release();
- g_lamexp_ipc_ptr.semaphore_write_mutex->release();
-
- return 0;
-}
-
-/*
- * IPC send message
- */
-void lamexp_ipc_send(unsigned int command, const char* message)
-{
- QReadLocker readLock(&g_lamexp_ipc_ptr.lock);
-
- if(!g_lamexp_ipc_ptr.sharedmem || !g_lamexp_ipc_ptr.semaphore_read || !g_lamexp_ipc_ptr.semaphore_write || !g_lamexp_ipc_ptr.semaphore_read_mutex || !g_lamexp_ipc_ptr.semaphore_write_mutex)
- {
- THROW("Shared memory for IPC not initialized yet.");
- }
-
- lamexp_ipc_data_t ipc_data;
- memset(&ipc_data, 0, sizeof(lamexp_ipc_data_t));
- ipc_data.command = command;
-
- if(message)
- {
- strncpy_s(ipc_data.parameter, 4096, message, _TRUNCATE);
- }
-
- if(g_lamexp_ipc_ptr.semaphore_write->acquire())
- {
- if(g_lamexp_ipc_ptr.semaphore_write_mutex->acquire())
- {
- lamexp_ipc_t *ptr = reinterpret_cast(g_lamexp_ipc_ptr.sharedmem->data());
- memcpy(&ptr->data[ptr->pos_write], &ipc_data, sizeof(lamexp_ipc_data_t));
- ptr->pos_write = (ptr->pos_write + 1) % g_lamexp_ipc_slots;
- g_lamexp_ipc_ptr.semaphore_read->release();
- g_lamexp_ipc_ptr.semaphore_write_mutex->release();
- }
- }
-}
-
-/*
- * IPC read message
- */
-void lamexp_ipc_read(unsigned int *command, char* message, size_t buffSize)
-{
- QReadLocker readLock(&g_lamexp_ipc_ptr.lock);
-
- *command = 0;
- message[0] = '\0';
-
- if(!g_lamexp_ipc_ptr.sharedmem || !g_lamexp_ipc_ptr.semaphore_read || !g_lamexp_ipc_ptr.semaphore_write || !g_lamexp_ipc_ptr.semaphore_read_mutex || !g_lamexp_ipc_ptr.semaphore_write_mutex)
- {
- THROW("Shared memory for IPC not initialized yet.");
- }
-
- lamexp_ipc_data_t ipc_data;
- memset(&ipc_data, 0, sizeof(lamexp_ipc_data_t));
-
- if(g_lamexp_ipc_ptr.semaphore_read->acquire())
- {
- if(g_lamexp_ipc_ptr.semaphore_read_mutex->acquire())
- {
- lamexp_ipc_t *ptr = reinterpret_cast(g_lamexp_ipc_ptr.sharedmem->data());
- memcpy(&ipc_data, &ptr->data[ptr->pos_read], sizeof(lamexp_ipc_data_t));
- ptr->pos_read = (ptr->pos_read + 1) % g_lamexp_ipc_slots;
- g_lamexp_ipc_ptr.semaphore_write->release();
- g_lamexp_ipc_ptr.semaphore_read_mutex->release();
-
- if(!(ipc_data.reserved_1 || ipc_data.reserved_2))
- {
- *command = ipc_data.command;
- strncpy_s(message, buffSize, ipc_data.parameter, _TRUNCATE);
- }
- else
- {
- qWarning("Malformed IPC message, will be ignored");
- }
- }
- }
-}
-
-/*
- * Check for LameXP "portable" mode
- */
-bool lamexp_portable_mode(void)
-{
- QReadLocker readLock(&g_lamexp_portable.lock);
-
- if(g_lamexp_portable.bInitialized)
- {
- return g_lamexp_portable.bPortableModeEnabled;
- }
-
- readLock.unlock();
- QWriteLocker writeLock(&g_lamexp_portable.lock);
-
- if(!g_lamexp_portable.bInitialized)
- {
- if(VER_LAMEXP_PORTABLE_EDITION)
- {
- qWarning("LameXP portable edition!\n");
- g_lamexp_portable.bPortableModeEnabled = true;
- }
- else
- {
- QString baseName = QFileInfo(QApplication::applicationFilePath()).completeBaseName();
- int idx1 = baseName.indexOf("lamexp", 0, Qt::CaseInsensitive);
- int idx2 = baseName.lastIndexOf("portable", -1, Qt::CaseInsensitive);
- g_lamexp_portable.bPortableModeEnabled = (idx1 >= 0) && (idx2 >= 0) && (idx1 < idx2);
- }
- g_lamexp_portable.bInitialized = true;
- }
-
- return g_lamexp_portable.bPortableModeEnabled;
-}
-
-/*
- * Get a random string
- */
-QString lamexp_rand_str(const bool bLong)
-{
- const QUuid uuid = QUuid::createUuid().toString();
-
- const unsigned int u1 = uuid.data1;
- const unsigned int u2 = (((unsigned int)(uuid.data2)) << 16) | ((unsigned int)(uuid.data3));
- const unsigned int u3 = (((unsigned int)(uuid.data4[0])) << 24) | (((unsigned int)(uuid.data4[1])) << 16) | (((unsigned int)(uuid.data4[2])) << 8) | ((unsigned int)(uuid.data4[3]));
- const unsigned int u4 = (((unsigned int)(uuid.data4[4])) << 24) | (((unsigned int)(uuid.data4[5])) << 16) | (((unsigned int)(uuid.data4[6])) << 8) | ((unsigned int)(uuid.data4[7]));
-
- return bLong ? QString().sprintf("%08x%08x%08x%08x", u1, u2, u3, u4) : QString().sprintf("%08x%08x", (u1 ^ u2), (u3 ^ u4));
-}
-
-
-/*
- * Try to initialize the folder (with *write* access)
- */
-static QString lamexp_try_init_folder(const QString &folderPath)
-{
- bool success = false;
-
- const QFileInfo folderInfo(folderPath);
- const QDir folderDir(folderInfo.absoluteFilePath());
-
- //Create folder, if it does *not* exist yet
- if(!folderDir.exists())
- {
- folderDir.mkpath(".");
- }
-
- //Make sure folder exists now *and* is writable
- if(folderDir.exists())
- {
- QFile testFile(folderDir.absoluteFilePath(QString("~%1.tmp").arg(lamexp_rand_str())));
- if(testFile.open(QIODevice::ReadWrite))
- {
- const QByteArray testData = QByteArray("Lorem ipsum dolor sit amet, consectetur, adipisci velit!");
- if(testFile.write(testData) >= strlen(testData))
- {
- success = true;
- testFile.remove();
- }
- testFile.close();
- }
- }
-
- return (success ? folderDir.canonicalPath() : QString());
-}
-
-/*
- * Initialize LameXP temp folder
- */
-#define INIT_TEMP_FOLDER(OUT,TMP) do \
-{ \
- (OUT) = lamexp_try_init_folder(QString("%1/%2").arg((TMP), lamexp_rand_str())); \
-} \
-while(0)
-
-/*
- * Get LameXP temp folder
- */
-const QString &lamexp_temp_folder2(void)
-{
- QReadLocker readLock(&g_lamexp_temp_folder.lock);
-
- //Already initialized?
- if(g_lamexp_temp_folder.path && (!g_lamexp_temp_folder.path->isEmpty()))
- {
- if(QDir(*g_lamexp_temp_folder.path).exists())
- {
- return *g_lamexp_temp_folder.path;
- }
- }
-
- //Obtain the write lock to initilaize
- readLock.unlock();
- QWriteLocker writeLock(&g_lamexp_temp_folder.lock);
-
- //Still uninitilaized?
- if(g_lamexp_temp_folder.path && (!g_lamexp_temp_folder.path->isEmpty()))
- {
- if(QDir(*g_lamexp_temp_folder.path).exists())
- {
- return *g_lamexp_temp_folder.path;
- }
- }
-
- //Create the string, if not done yet
- if(!g_lamexp_temp_folder.path)
- {
- g_lamexp_temp_folder.path = new QString();
- }
-
- g_lamexp_temp_folder.path->clear();
-
- //Try the %TMP% or %TEMP% directory first
- QString tempPath = lamexp_try_init_folder(QDir::temp().absolutePath());
- if(!tempPath.isEmpty())
- {
- INIT_TEMP_FOLDER(*g_lamexp_temp_folder.path, tempPath);
- }
-
- //Otherwise create TEMP folder in %LOCALAPPDATA%
- if(g_lamexp_temp_folder.path->isEmpty())
- {
- tempPath = lamexp_try_init_folder(QString("%1/Temp").arg(lamexp_known_folder(lamexp_folder_localappdata)));
- if(!tempPath.isEmpty())
- {
- INIT_TEMP_FOLDER(*g_lamexp_temp_folder.path, tempPath);
- }
- }
-
- //Failed to create TEMP folder?
- if(g_lamexp_temp_folder.path->isEmpty())
- {
- qFatal("Temporary directory could not be initialized !!!");
- }
-
- return *g_lamexp_temp_folder.path;
-}
-
-/*
- * Clean folder
- */
-bool lamexp_clean_folder(const QString &folderPath)
-{
- QDir tempFolder(folderPath);
- if(tempFolder.exists())
- {
- QFileInfoList entryList = tempFolder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
-
- for(int i = 0; i < entryList.count(); i++)
- {
- if(entryList.at(i).isDir())
- {
- lamexp_clean_folder(entryList.at(i).canonicalFilePath());
- }
- else
- {
- for(int j = 0; j < 3; j++)
- {
- if(lamexp_remove_file(entryList.at(i).canonicalFilePath()))
- {
- break;
- }
- }
- }
- }
- return tempFolder.rmdir(".");
- }
- return true;
-}
-
-/*
- * Register tool
- */
-void lamexp_register_tool(const QString &toolName, LockedFile *file, unsigned int version, const QString *tag)
-{
- QWriteLocker writeLock(&g_lamexp_tools.lock);
-
- if(!g_lamexp_tools.registry) g_lamexp_tools.registry = new QMap();
- if(!g_lamexp_tools.versions) g_lamexp_tools.versions = new QMap();
- if(!g_lamexp_tools.tags) g_lamexp_tools.tags = new QMap();
-
- if(g_lamexp_tools.registry->contains(toolName.toLower()))
- {
- THROW("lamexp_register_tool: Tool is already registered!");
- }
-
- g_lamexp_tools.registry->insert(toolName.toLower(), file);
- g_lamexp_tools.versions->insert(toolName.toLower(), version);
- g_lamexp_tools.tags->insert(toolName.toLower(), (tag) ? (*tag) : QString());
-}
-
-/*
- * Check for tool
- */
-bool lamexp_check_tool(const QString &toolName)
-{
- QReadLocker readLock(&g_lamexp_tools.lock);
- return (g_lamexp_tools.registry) ? g_lamexp_tools.registry->contains(toolName.toLower()) : false;
-}
-
-/*
- * Lookup tool path
- */
-const QString lamexp_lookup_tool(const QString &toolName)
-{
- QReadLocker readLock(&g_lamexp_tools.lock);
-
- if(g_lamexp_tools.registry)
- {
- if(g_lamexp_tools.registry->contains(toolName.toLower()))
- {
- return g_lamexp_tools.registry->value(toolName.toLower())->filePath();
- }
- else
- {
- return QString();
- }
- }
- else
- {
- return QString();
- }
-}
-
-/*
- * Lookup tool version
- */
-unsigned int lamexp_tool_version(const QString &toolName, QString *tag)
-{
- QReadLocker readLock(&g_lamexp_tools.lock);
- if(tag) tag->clear();
-
- if(g_lamexp_tools.versions)
- {
- if(g_lamexp_tools.versions->contains(toolName.toLower()))
- {
- if(tag)
- {
- if(g_lamexp_tools.tags->contains(toolName.toLower())) *tag = g_lamexp_tools.tags->value(toolName.toLower());
- }
- return g_lamexp_tools.versions->value(toolName.toLower());
- }
- else
- {
- return UINT_MAX;
- }
- }
- else
- {
- return UINT_MAX;
- }
-}
-
-/*
- * Version number to human-readable string
- */
-const QString lamexp_version2string(const QString &pattern, unsigned int version, const QString &defaultText, const QString *tag)
-{
- if(version == UINT_MAX)
- {
- return defaultText;
- }
-
- QString result = pattern;
- int digits = result.count("?", Qt::CaseInsensitive);
-
- if(digits < 1)
- {
- return result;
- }
-
- int pos = 0;
- QString versionStr = QString().sprintf(QString().sprintf("%%0%du", digits).toLatin1().constData(), version);
- int index = result.indexOf("?", Qt::CaseInsensitive);
-
- while(index >= 0 && pos < versionStr.length())
- {
- result[index] = versionStr[pos++];
- index = result.indexOf("?", Qt::CaseInsensitive);
- }
-
- if(tag)
- {
- result.replace(QChar('#'), *tag, Qt::CaseInsensitive);
- }
-
- return result;
-}
-
-/*
- * Register a new translation
- */
-bool lamexp_translation_register(const QString &langId, const QString &qmFile, const QString &langName, unsigned int &systemId, unsigned int &country)
-{
- QWriteLocker writeLockTranslations(&g_lamexp_translation.lock);
-
- if(qmFile.isEmpty() || langName.isEmpty() || systemId < 1)
- {
- return false;
- }
-
- if(!g_lamexp_translation.files) g_lamexp_translation.files = new QMap();
- if(!g_lamexp_translation.names) g_lamexp_translation.names = new QMap();
- if(!g_lamexp_translation.sysid) g_lamexp_translation.sysid = new QMap();
- if(!g_lamexp_translation.cntry) g_lamexp_translation.cntry = new QMap();
-
- g_lamexp_translation.files->insert(langId, qmFile);
- g_lamexp_translation.names->insert(langId, langName);
- g_lamexp_translation.sysid->insert(langId, systemId);
- g_lamexp_translation.cntry->insert(langId, country);
-
- return true;
-}
-
-/*
- * Get list of all translations
- */
-QStringList lamexp_query_translations(void)
-{
- QReadLocker readLockTranslations(&g_lamexp_translation.lock);
- return (g_lamexp_translation.files) ? g_lamexp_translation.files->keys() : QStringList();
-}
-
-/*
- * Get translation name
- */
-QString lamexp_translation_name(const QString &langId)
-{
- QReadLocker readLockTranslations(&g_lamexp_translation.lock);
- return (g_lamexp_translation.names) ? g_lamexp_translation.names->value(langId.toLower(), QString()) : QString();
-}
-
-/*
- * Get translation system id
- */
-unsigned int lamexp_translation_sysid(const QString &langId)
-{
- QReadLocker readLockTranslations(&g_lamexp_translation.lock);
- return (g_lamexp_translation.sysid) ? g_lamexp_translation.sysid->value(langId.toLower(), 0) : 0;
-}
-
-/*
- * Get translation script id
- */
-unsigned int lamexp_translation_country(const QString &langId)
-{
- QReadLocker readLockTranslations(&g_lamexp_translation.lock);
- return (g_lamexp_translation.cntry) ? g_lamexp_translation.cntry->value(langId.toLower(), 0) : 0;
-}
-
-/*
- * Install a new translator
- */
-bool lamexp_install_translator(const QString &langId)
-{
- bool success = false;
- const QString qmFileToPath(":/localization/%1");
-
- if(langId.isEmpty() || langId.toLower().compare(LAMEXP_DEFAULT_LANGID) == 0)
- {
- success = lamexp_install_translator_from_file(qmFileToPath.arg(LAMEXP_DEFAULT_TRANSLATION));
- }
- else
- {
- QReadLocker readLock(&g_lamexp_translation.lock);
- QString qmFile = (g_lamexp_translation.files) ? g_lamexp_translation.files->value(langId.toLower(), QString()) : QString();
- readLock.unlock();
-
- if(!qmFile.isEmpty())
- {
- success = lamexp_install_translator_from_file(qmFileToPath.arg(qmFile));
- }
- else
- {
- qWarning("Translation '%s' not available!", langId.toLatin1().constData());
- }
- }
-
- return success;
-}
-
-/*
- * Install a new translator from file
- */
-bool lamexp_install_translator_from_file(const QString &qmFile)
-{
- QWriteLocker writeLock(&g_lamexp_currentTranslator.lock);
- bool success = false;
-
- if(!g_lamexp_currentTranslator.instance)
- {
- g_lamexp_currentTranslator.instance = new QTranslator();
- }
-
- if(!qmFile.isEmpty())
- {
- QString qmPath = QFileInfo(qmFile).canonicalFilePath();
- QApplication::removeTranslator(g_lamexp_currentTranslator.instance);
- if(success = g_lamexp_currentTranslator.instance->load(qmPath))
- {
- QApplication::installTranslator(g_lamexp_currentTranslator.instance);
- }
- else
- {
- qWarning("Failed to load translation:\n\"%s\"", qmPath.toLatin1().constData());
- }
- }
- else
- {
- QApplication::removeTranslator(g_lamexp_currentTranslator.instance);
- success = true;
- }
-
- return success;
-}
-
const QStringList &lamexp_arguments(void)
{
QReadLocker readLock(&g_lamexp_argv.lock);
@@ -2405,178 +1375,6 @@ bool lamexp_shutdown_computer(const QString &message, const unsigned long timeou
return false;
}
-/*
- * Make a window blink (to draw user's attention)
- */
-void lamexp_blink_window(QWidget *poWindow, unsigned int count, unsigned int delay)
-{
- static QMutex blinkMutex;
-
- const double maxOpac = 1.0;
- const double minOpac = 0.3;
- const double delOpac = 0.1;
-
- if(!blinkMutex.tryLock())
- {
- qWarning("Blinking is already in progress, skipping!");
- return;
- }
-
- try
- {
- const int steps = static_cast(ceil(maxOpac - minOpac) / delOpac);
- const int sleep = static_cast(floor(static_cast(delay) / static_cast(steps)));
- const double opacity = poWindow->windowOpacity();
-
- for(unsigned int i = 0; i < count; i++)
- {
- for(double x = maxOpac; x >= minOpac; x -= delOpac)
- {
- poWindow->setWindowOpacity(x);
- QApplication::processEvents();
- Sleep(sleep);
- }
-
- for(double x = minOpac; x <= maxOpac; x += delOpac)
- {
- poWindow->setWindowOpacity(x);
- QApplication::processEvents();
- Sleep(sleep);
- }
- }
-
- poWindow->setWindowOpacity(opacity);
- QApplication::processEvents();
- blinkMutex.unlock();
- }
- catch(...)
- {
- blinkMutex.unlock();
- qWarning("Exception error while blinking!");
- }
-}
-
-/*
- * Remove forbidden characters from a filename
- */
-const QString lamexp_clean_filename(const QString &str)
-{
- QString newStr(str);
- QRegExp rx("\"(.+)\"");
- rx.setMinimal(true);
-
- newStr.replace("\\", "-");
- newStr.replace(" / ", ", ");
- newStr.replace("/", ",");
- newStr.replace(":", "-");
- newStr.replace("*", "x");
- newStr.replace("?", "");
- newStr.replace("<", "[");
- newStr.replace(">", "]");
- newStr.replace("|", "!");
- newStr.replace(rx, "`\\1´");
- newStr.replace("\"", "'");
-
- return newStr.simplified();
-}
-
-/*
- * Remove forbidden characters from a file path
- */
-const QString lamexp_clean_filepath(const QString &str)
-{
- QStringList parts = QString(str).replace("\\", "/").split("/");
-
- for(int i = 0; i < parts.count(); i++)
- {
- parts[i] = lamexp_clean_filename(parts[i]);
- }
-
- return parts.join("/");
-}
-
-/*
- * Get a list of all available Qt Text Codecs
- */
-QStringList lamexp_available_codepages(bool noAliases)
-{
- QStringList codecList;
-
- QList availableCodecs = QTextCodec::availableCodecs();
- while(!availableCodecs.isEmpty())
- {
- QByteArray current = availableCodecs.takeFirst();
- if(!(current.startsWith("system") || current.startsWith("System")))
- {
- codecList << QString::fromLatin1(current.constData(), current.size());
- if(noAliases)
- {
- if(QTextCodec *currentCodec = QTextCodec::codecForName(current.constData()))
- {
-
- QList aliases = currentCodec->aliases();
- while(!aliases.isEmpty()) availableCodecs.removeAll(aliases.takeFirst());
- }
- }
- }
- }
-
- return codecList;
-}
-
-/*
- * Robert Jenkins' 96 bit Mix Function
- * Source: http://www.concentric.net/~Ttwang/tech/inthash.htm
- */
-static unsigned int lamexp_mix(const unsigned int x, const unsigned int y, const unsigned int z)
-{
- unsigned int a = x;
- unsigned int b = y;
- unsigned int c = z;
-
- a=a-b; a=a-c; a=a^(c >> 13);
- b=b-c; b=b-a; b=b^(a << 8);
- c=c-a; c=c-b; c=c^(b >> 13);
- a=a-b; a=a-c; a=a^(c >> 12);
- b=b-c; b=b-a; b=b^(a << 16);
- c=c-a; c=c-b; c=c^(b >> 5);
- a=a-b; a=a-c; a=a^(c >> 3);
- b=b-c; b=b-a; b=b^(a << 10);
- c=c-a; c=c-b; c=c^(b >> 15);
-
- return c;
-}
-
-/*
- * Seeds the random number generator
- * Note: Altough rand_s() doesn't need a seed, this must be called pripr to lamexp_rand(), just to to be sure!
- */
-void lamexp_seed_rand(void)
-{
- qsrand(lamexp_mix(clock(), time(NULL), _getpid()));
-}
-
-/*
- * Returns a randum number
- * Note: This function uses rand_s() if available, but falls back to qrand() otherwise
- */
-unsigned int lamexp_rand(void)
-{
- quint32 rnd = 0;
-
- if(rand_s(&rnd) == 0)
- {
- return rnd;
- }
-
- for(size_t i = 0; i < sizeof(unsigned int); i++)
- {
- rnd = (rnd << 8) ^ qrand();
- }
-
- return rnd;
-}
-
/*
* Determines the current date, resistant against certain manipulations
*/
@@ -2640,31 +1438,6 @@ QDate lamexp_current_date_safe(void)
return (currentDate >= processDate) ? currentDate : processDate;
}
-
-/*
- * Natural Order String Comparison - the 'lessThan' helper function
- */
-static bool lamexp_natural_string_sort_helper(const QString &str1, const QString &str2)
-{
- return (strnatcmp(QWCHAR(str1), QWCHAR(str2)) < 0);
-}
-
-/*
- * Natural Order String Comparison - the 'lessThan' helper function *with* case folding
- */
-static bool lamexp_natural_string_sort_helper_fold_case(const QString &str1, const QString &str2)
-{
- return (strnatcasecmp(QWCHAR(str1), QWCHAR(str2)) < 0);
-}
-
-/*
- * Natural Order String Comparison - the main sorting function
- */
-void lamexp_natural_string_sort(QStringList &list, const bool bIgnoreCase)
-{
- qSort(list.begin(), list.end(), bIgnoreCase ? lamexp_natural_string_sort_helper_fold_case : lamexp_natural_string_sort_helper);
-}
-
/*
* Suspend calling thread for N milliseconds
*/
@@ -3052,101 +1825,6 @@ bool lamexp_open_media_file(const QString &mediaFilePath)
return false;
}
-/*
- * Setup QPorcess object
- */
-void lamexp_init_process(QProcess &process, const QString &wokringDir)
-{
- //Environment variable names
- static const char *const s_envvar_names[] =
- {
- "WGETRC", "SYSTEM_WGETRC", "HTTP_PROXY", "FTP_PROXY", "NO_PROXY", "GNUPGHOME", "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LANG", NULL
- };
-
- const QString tempDir = QDir::toNativeSeparators(lamexp_temp_folder2());
-
- QProcessEnvironment env = process.processEnvironment();
- if(env.isEmpty()) env = QProcessEnvironment::systemEnvironment();
-
- //Setup TEMP directory
- env.insert("TEMP", tempDir);
- env.insert("TMP", tempDir);
- env.insert("TMPDIR", tempDir);
- env.insert("HOME", tempDir);
- env.insert("USERPROFILE", tempDir);
- env.insert("HOMEPATH", tempDir);
-
- //Setup PATH variable
- const QString path = env.value("PATH", QString());
- env.insert("PATH", path.isEmpty() ? tempDir : QString("%1;%2").arg(tempDir, path));
-
- //Clean a number of enviroment variables that might affect our tools
- for(size_t i = 0; s_envvar_names[i]; i++)
- {
- env.remove(QString::fromLatin1(s_envvar_names[i]));
- env.remove(QString::fromLatin1(s_envvar_names[i]).toLower());
- }
-
- process.setWorkingDirectory(wokringDir);
- process.setProcessChannelMode(QProcess::MergedChannels);
- process.setReadChannel(QProcess::StandardOutput);
- process.setProcessEnvironment(env);
-}
-
-/*
- * Entry point checks
- */
-static DWORD lamexp_entry_check(void);
-static DWORD g_lamexp_entry_check_result = lamexp_entry_check();
-static DWORD g_lamexp_entry_check_flag = 0x789E09B2;
-static DWORD lamexp_entry_check(void)
-{
- volatile DWORD retVal = 0xA199B5AF;
- if(g_lamexp_entry_check_flag != 0x8761F64D)
- {
- lamexp_fatal_exit(L"Application initialization has failed, take care!");
- }
- return retVal;
-}
-
-/*
- * Application entry point (runs before static initializers)
- */
-extern "C"
-{
- int WinMainCRTStartup(void);
-
- int lamexp_entry_point(void)
- {
- if((!LAMEXP_DEBUG) && lamexp_check_for_debugger())
- {
- lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
- }
- if(g_lamexp_entry_check_flag != 0x789E09B2)
- {
- lamexp_fatal_exit(L"Application initialization has failed, take care!");
- }
-
- //Zero *before* constructors are called
- LAMEXP_ZERO_MEMORY(g_lamexp_argv);
- LAMEXP_ZERO_MEMORY(g_lamexp_tools);
- LAMEXP_ZERO_MEMORY(g_lamexp_currentTranslator);
- LAMEXP_ZERO_MEMORY(g_lamexp_translation);
- LAMEXP_ZERO_MEMORY(g_lamexp_known_folder);
- LAMEXP_ZERO_MEMORY(g_lamexp_temp_folder);
- LAMEXP_ZERO_MEMORY(g_lamexp_ipc_ptr);
- LAMEXP_ZERO_MEMORY(g_lamexp_os_version);
- LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled);
- LAMEXP_ZERO_MEMORY(g_lamexp_portable);
-
- //Make sure we will pass the check
- g_lamexp_entry_check_flag = ~g_lamexp_entry_check_flag;
-
- //Now initialize the C Runtime library!
- return WinMainCRTStartup();
- }
-}
-
/*
* Fatal application exit
*/
@@ -3179,25 +1857,6 @@ void lamexp_fatal_exit(const wchar_t* exitMessage, const wchar_t* errorBoxMessag
Sleep(INFINITE);
}
-/*
- * Free all registered tools (final clean-up)
- */
-void lamexp_clean_all_tools(void)
-{
- if(g_lamexp_tools.registry)
- {
- QStringList keys = g_lamexp_tools.registry->keys();
- for(int i = 0; i < keys.count(); i++)
- {
- LockedFile *lf = g_lamexp_tools.registry->take(keys.at(i));
- LAMEXP_DELETE(lf);
- }
- g_lamexp_tools.registry->clear();
- g_lamexp_tools.versions->clear();
- g_lamexp_tools.tags->clear();
- }
-}
-
/*
* Finalization function (final clean-up)
*/
@@ -3206,63 +1865,41 @@ void lamexp_finalization(void)
qDebug("lamexp_finalization()");
//Free all tools
- if(g_lamexp_tools.registry)
- {
- lamexp_clean_all_tools();
- LAMEXP_DELETE(g_lamexp_tools.registry);
- LAMEXP_DELETE(g_lamexp_tools.versions);
- LAMEXP_DELETE(g_lamexp_tools.tags);
- }
+ lamexp_clean_all_tools();
//Delete temporary files
- if(g_lamexp_temp_folder.path)
+ const QString &tempFolder = lamexp_temp_folder2();
+ if(!tempFolder.isEmpty())
{
- if(!g_lamexp_temp_folder.path->isEmpty())
+ bool success = false;
+ for(int i = 0; i < 100; i++)
{
- bool success = false;
- for(int i = 0; i < 100; i++)
+ if(lamexp_clean_folder(tempFolder))
{
- if(lamexp_clean_folder(*g_lamexp_temp_folder.path))
- {
- success = true;
- break;
- }
- lamexp_sleep(100);
- }
- if(!success)
- {
- MessageBoxW(NULL, L"Sorry, LameXP was unable to clean up all temporary files. Some residual files in your TEMP directory may require manual deletion!", L"LameXP", MB_ICONEXCLAMATION|MB_TOPMOST);
- lamexp_exec_shell(NULL, *g_lamexp_temp_folder.path, QString(), QString(), true);
+ success = true;
+ break;
}
+ lamexp_sleep(100);
+ }
+ if(!success)
+ {
+ MessageBoxW(NULL, L"Sorry, LameXP was unable to clean up all temporary files. Some residual files in your TEMP directory may require manual deletion!", L"LameXP", MB_ICONEXCLAMATION|MB_TOPMOST);
+ lamexp_exec_shell(NULL, tempFolder, QString(), QString(), true);
}
- LAMEXP_DELETE(g_lamexp_temp_folder.path);
}
//Clear folder cache
LAMEXP_DELETE(g_lamexp_known_folder.knownFolders);
//Clear languages
- if(g_lamexp_currentTranslator.instance)
- {
- QApplication::removeTranslator(g_lamexp_currentTranslator.instance);
- LAMEXP_DELETE(g_lamexp_currentTranslator.instance);
- }
- LAMEXP_DELETE(g_lamexp_translation.files);
- LAMEXP_DELETE(g_lamexp_translation.names);
- LAMEXP_DELETE(g_lamexp_translation.cntry);
- LAMEXP_DELETE(g_lamexp_translation.sysid);
+ lamexp_clean_all_translations();
//Destroy Qt application object
QApplication *application = dynamic_cast(QApplication::instance());
LAMEXP_DELETE(application);
//Detach from shared memory
- if(g_lamexp_ipc_ptr.sharedmem) g_lamexp_ipc_ptr.sharedmem->detach();
- LAMEXP_DELETE(g_lamexp_ipc_ptr.sharedmem);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
- LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
+ lamexp_ipc_exit();
//Free STDOUT and STDERR buffers
if(g_lamexp_console_attached)
@@ -3288,6 +1925,9 @@ void lamexp_finalization(void)
//Free CLI Arguments
LAMEXP_DELETE(g_lamexp_argv.list);
+
+ //Free TEMP folder
+ lamexp_temp_folder_clear();
}
/*
@@ -3310,3 +1950,39 @@ unsigned long lamexp_dbg_private_bytes(void)
THROW("Cannot call this function in a non-debug build!");
#endif //LAMEXP_DEBUG
}
+
+/*
+ * Output string to debugger [debug only]
+ */
+void lamexp_dbg_dbg_output_string(const char* format, ...)
+{
+#if LAMEXP_DEBUG
+ char buffer[256];
+ va_list args;
+ va_start (args, format);
+ vsnprintf_s(buffer, 256, _TRUNCATE, format, args);
+ OutputDebugStringA(buffer);
+ va_end(args);
+#else
+ THROW("Cannot call this function in a non-debug build!");
+#endif //LAMEXP_DEBUG
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+///////////////////////////////////////////////////////////////////////////////
+
+extern "C" void _lamexp_global_init_win32(void)
+{
+ if((!LAMEXP_DEBUG) && lamexp_check_for_debugger())
+ {
+ lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
+ }
+
+ //Zero *before* constructors are called
+ LAMEXP_ZERO_MEMORY(g_lamexp_argv);
+ LAMEXP_ZERO_MEMORY(g_lamexp_known_folder);
+ LAMEXP_ZERO_MEMORY(g_lamexp_os_version);
+ LAMEXP_ZERO_MEMORY(g_lamexp_wine);
+ LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled);
+}
diff --git a/src/JobObject.cpp b/src/JobObject.cpp
index 292c5733..0f51da06 100644
--- a/src/JobObject.cpp
+++ b/src/JobObject.cpp
@@ -71,16 +71,54 @@ JobObject::~JobObject(void)
}
bool JobObject::addProcessToJob(const QProcess *proc)
+{
+ if(!m_hJobObject)
+ {
+ qWarning("Cannot assign process to job: No job bject available!");
+ return false;
+ }
+
+ if(Q_PID pid = proc->pid())
+ {
+ DWORD exitCode;
+ if(!GetExitCodeProcess(pid->hProcess, &exitCode))
+ {
+ qWarning("Cannot assign process to job: Failed to query process status!");
+ return false;
+ }
+
+ if(exitCode != STILL_ACTIVE)
+ {
+ qWarning("Cannot assign process to job: Process is not running anymore!");
+ return false;
+ }
+
+ if(!AssignProcessToJobObject(m_hJobObject, pid->hProcess))
+ {
+ qWarning("Failed to assign process to job object!");
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ qWarning("Cannot assign process to job: Process handle not available!");
+ return false;
+ }
+}
+
+bool JobObject::terminateJob(unsigned int exitCode)
{
if(m_hJobObject)
{
- if(AssignProcessToJobObject(m_hJobObject, proc->pid()->hProcess))
+ if(TerminateJobObject(m_hJobObject, exitCode))
{
return true;
}
else
{
- qWarning("Failed to assign process to job object!");
+ qWarning("Failed to terminate job object!");
return false;
}
}
diff --git a/src/JobObject.h b/src/JobObject.h
index 5f73ab27..9d1bf602 100644
--- a/src/JobObject.h
+++ b/src/JobObject.h
@@ -31,6 +31,7 @@ public:
~JobObject(void);
bool addProcessToJob(const QProcess *proc);
+ bool terminateJob(unsigned int exitCode);
private:
void *m_hJobObject;
diff --git a/src/Main.cpp b/src/Main.cpp
index 6ed798d6..46e88e94 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -40,14 +40,6 @@
#include
#include
-//Windows includes
-#define NOMINMAX
-#define WIN32_LEAN_AND_MEAN
-#include
-
-//Forward declaration
-LONG WINAPI lamexp_exception_handler(__in struct _EXCEPTION_POINTERS *ExceptionInfo);
-
///////////////////////////////////////////////////////////////////////////////
// Main function
///////////////////////////////////////////////////////////////////////////////
@@ -58,9 +50,6 @@ static int lamexp_main(int argc, char* argv[])
int iShutdown = shutdownFlag_None;
bool bAccepted = true;
- //Increase "main" thread priority
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
-
//Get CLI arguments
const QStringList &arguments = lamexp_arguments();
@@ -272,16 +261,14 @@ int main(int argc, char* argv[])
{
__try
{
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
- SetUnhandledExceptionFilter(lamexp_exception_handler);
- _set_invalid_parameter_handler(lamexp_invalid_param_handler);
+ lamexp_init_error_handlers();
return _main(argc, argv);
}
__except(1)
{
fflush(stdout);
fflush(stderr);
- fprintf(stderr, "\nGURU MEDITATION !!!\n\nUnhandeled structured exception error! [code: 0x%X]\n", GetExceptionCode());
+ fprintf(stderr, "\nGURU MEDITATION !!!\n\nUnhandeled structured exception error!\n");
lamexp_fatal_exit(L"Unhandeled structured exception error, application will exit!");
}
}
diff --git a/src/Thread_Initialization.cpp b/src/Thread_Initialization.cpp
index 0912e276..a3e03a90 100644
--- a/src/Thread_Initialization.cpp
+++ b/src/Thread_Initialization.cpp
@@ -221,7 +221,6 @@ InitializationThread::InitializationThread(const lamexp_cpu_t *cpuFeatures)
#ifdef ENABLE_BENCHMARK
#define DO_INIT_FUNCT runBenchmark
-void lamexp_clean_all_tools(void);
#else //ENABLE_BENCHMARK
#define DO_INIT_FUNCT doInit
#endif //ENABLE_BENCHMARK
@@ -314,7 +313,7 @@ double InitializationThread::doInit(const size_t threadCount)
QThreadPool *pool = new QThreadPool();
pool->setMaxThreadCount((threadCount > 0) ? threadCount : qBound(2U, cores2threads(m_cpuFeatures.count), EXPECTED_TOOL_COUNT));
- //qWarning("Using %u threads for extraction.", pool->maxThreadCount());
+ /* qWarning("Using %u threads for extraction.", pool->maxThreadCount()); */
LockedFile::selfTest();
ExtractorTask::clearFlags();