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 - + Executable '%1' doesn't support Windows compatibility mode. - + Executable '%1' requires Qt v%2, but found Qt v%3. - + Executable '%1' was built for Qt '%2', but found Qt '%3'. - + Executable '%1' requires Windows XP or later. 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 - + Executable '%1' doesn't support Windows compatibility mode. Plik wykonywalny '%1' nie dziaÅ‚a w trybie kompatybilnoÅ›ci z Windows. - + Executable '%1' requires Qt v%2, but found Qt v%3. Plik wykonywalny '%1' wymaga Qt v%2, znaleziono jednak Qt v%3. - + Executable '%1' was built for Qt '%2', but found Qt '%3'. Plik wykonywalny "%1" zostaÅ‚ skompilowany dla Qt "%2", znaleziono "%3". - + Executable '%1' requires Windows XP or later. 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 - + Executable '%1' doesn't support Windows compatibility mode. EXE-filen '%1' stöder inte Windows kompatibilitetsläge. - + Executable '%1' requires Qt v%2, but found Qt v%3. EXE-filen '%1' kräver Qt v%2, du har Qt v%3. - + Executable '%1' was built for Qt '%2', but found Qt '%3'. EXE-filen '%1' är byggd för Qt '%2', du har Qt '%3'. - + Executable '%1' requires Windows XP or later. 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();