OSDN Git Service

Updated changelog.
[lamexp/LameXP.git] / src / Global_Utils.cpp
index 31c7ca9..727401f 100644 (file)
@@ -1,12 +1,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 // LameXP - Audio Encoder Front-End
-// Copyright (C) 2004-2013 LoRd_MuldeR <MuldeR2@GMX.de>
+// Copyright (C) 2004-2023 LoRd_MuldeR <MuldeR2@GMX.de>
 //
 // This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
+// 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.
+// (at your option) any later version; always including the non-optional
+// LAMEXP GNU GENERAL PUBLIC LICENSE ADDENDUM. See "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
@@ -35,8 +35,9 @@
 #include <QUuid>
 #include <QWidget>
 
-//Natural sort
-#include "strnatcmp.h"
+//MUtils
+#include <MUtils/Global.h>
+#include <MUtils/OSSupport.h>
 
 //CRT includes
 #include <time.h>
 // GLOBAL VARS
 ///////////////////////////////////////////////////////////////////////////////
 
-//%TEMP% folder
-static struct
-{
-       QString *path;
-       QReadWriteLock lock;
-}
-g_lamexp_temp_folder;
-
-static struct
-{
-       QIcon *appIcon;
-       QReadWriteLock lock;
-}
-g_lamexp_app_icon;
+static QScopedPointer<QIcon> g_lamexp_icon_data;
+static QReadWriteLock        g_lamexp_icon_lock;
 
 ///////////////////////////////////////////////////////////////////////////////
 // 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)
-{
-       static const char *TEST_DATA = "Lorem ipsum dolor sit amet, consectetur, adipisci velit!";
-       
-       bool success = false;
-
-       const QFileInfo folderInfo(folderPath);
-       const QDir folderDir(folderInfo.absoluteFilePath());
-
-       //Create folder, if it does *not* exist yet
-       for(int i = 0; (i < 16) && (!folderDir.exists()); i++)
-       {
-               folderDir.mkpath(".");
-       }
-
-       //Make sure folder exists now *and* is writable
-       if(folderDir.exists())
-       {
-               const QByteArray testData = QByteArray(TEST_DATA);
-               for(int i = 0; (i < 32) && (!success); i++)
-               {
-                       QFile testFile(folderDir.absoluteFilePath(QString("~%1.tmp").arg(lamexp_rand_str())));
-                       if(testFile.open(QIODevice::ReadWrite | QIODevice::Truncate))
-                       {
-                               if(testFile.write(testData) >= testData.size())
-                               {
-                                       success = true;
-                               }
-                               testFile.remove();
-                       }
-               }
-       }
-
-       return (success ? folderDir.canonicalPath() : QString());
-}
-
-/*
- * Initialize LameXP temp folder
- */
-#define INIT_TEMP_FOLDER_RAND(OUT_PTR, BASE_DIR) do \
-{ \
-       for(int _i = 0; _i < 128; _i++) \
-       { \
-               const QString _randDir =  QString("%1/%2").arg((BASE_DIR), lamexp_rand_str()); \
-               if(!QDir(_randDir).exists()) \
-               { \
-                       *(OUT_PTR) = lamexp_try_init_folder(_randDir); \
-                       if(!(OUT_PTR)->isEmpty()) break; \
-               } \
-       } \
-} \
-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_RAND(g_lamexp_temp_folder.path, tempPath);
-       }
-
-       //Otherwise create TEMP folder in %LOCALAPPDATA% or %SYSTEMROOT%
-       if(g_lamexp_temp_folder.path->isEmpty())
-       {
-               qWarning("%%TEMP%% directory not found -> trying fallback mode now!");
-               static const lamexp_known_folder_t folderId[2] = { lamexp_folder_localappdata, lamexp_folder_systroot_dir };
-               for(size_t id = 0; (g_lamexp_temp_folder.path->isEmpty() && (id < 2)); id++)
-               {
-                       const QString &knownFolder = lamexp_known_folder(folderId[id]);
-                       if(!knownFolder.isEmpty())
-                       {
-                               tempPath = lamexp_try_init_folder(QString("%1/Temp").arg(knownFolder));
-                               if(!tempPath.isEmpty())
-                               {
-                                       INIT_TEMP_FOLDER_RAND(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;
-}
-
-/*
- * Setup QPorcess object
- */
-void lamexp_init_process(QProcess &process, const QString &wokringDir, const bool bReplaceTempDir)
-{
-       //Environment variable names
-       static const char *const s_envvar_names_temp[] =
-       {
-               "TEMP", "TMP", "TMPDIR", "HOME", "USERPROFILE", "HOMEPATH", NULL
-       };
-       static const char *const s_envvar_names_remove[] =
-       {
-               "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
-       };
-
-       //Initialize environment
-       QProcessEnvironment env = process.processEnvironment();
-       if(env.isEmpty()) env = QProcessEnvironment::systemEnvironment();
-
-       //Clean a number of enviroment variables that might affect our tools
-       for(size_t i = 0; s_envvar_names_remove[i]; i++)
-       {
-               env.remove(QString::fromLatin1(s_envvar_names_remove[i]));
-               env.remove(QString::fromLatin1(s_envvar_names_remove[i]).toLower());
-       }
-
-       const QString tempDir = QDir::toNativeSeparators(lamexp_temp_folder2());
-
-       //Replace TEMP directory in environment
-       if(bReplaceTempDir)
-       {
-               for(size_t i = 0; s_envvar_names_temp[i]; i++)
-               {
-                       env.insert(s_envvar_names_temp[i], tempDir);
-               }
-       }
-
-       //Setup PATH variable
-       const QString path = env.value("PATH", QString()).trimmed();
-       env.insert("PATH", path.isEmpty() ? tempDir : QString("%1;%2").arg(tempDir, path));
-       
-       //Setup QPorcess object
-       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<QByteArray> 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<QByteArray> 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<int>(ceil(maxOpac - minOpac) / delOpac);
-               const int sleep = static_cast<int>(floor(static_cast<double>(delay) / static_cast<double>(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 | QDir::Hidden);
-
-               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)
@@ -537,124 +107,85 @@ static bool lamexp_thanksgiving(const QDate &date)
  */
 const QIcon &lamexp_app_icon(void)
 {
-       QReadLocker readLock(&g_lamexp_app_icon.lock);
+       QReadLocker readLock(&g_lamexp_icon_lock);
 
        //Already initialized?
-       if(g_lamexp_app_icon.appIcon)
+       if(!g_lamexp_icon_data.isNull())
        {
-               return *g_lamexp_app_icon.appIcon;
+               return *g_lamexp_icon_data;
        }
 
        readLock.unlock();
-       QWriteLocker writeLock(&g_lamexp_app_icon.lock);
+       QWriteLocker writeLock(&g_lamexp_icon_lock);
 
-       while(!g_lamexp_app_icon.appIcon)
+       while(g_lamexp_icon_data.isNull())
        {
                QDate currentDate = QDate::currentDate();
                QTime currentTime = QTime::currentTime();
        
                if(lamexp_thanksgiving(currentDate))
                {
-                       g_lamexp_app_icon.appIcon = new QIcon(":/MainIcon6.png");
+                       g_lamexp_icon_data.reset(new QIcon(":/MainIcon6.png"));
                }
                else if(((currentDate.month() == 12) && (currentDate.day() == 31) && (currentTime.hour() >= 20)) || ((currentDate.month() == 1) && (currentDate.day() == 1)  && (currentTime.hour() <= 19)))
                {
-                       g_lamexp_app_icon.appIcon = new QIcon(":/MainIcon5.png");
+                       g_lamexp_icon_data.reset(new QIcon(":/MainIcon5.png"));
                }
                else if(((currentDate.month() == 10) && (currentDate.day() == 31) && (currentTime.hour() >= 12)) || ((currentDate.month() == 11) && (currentDate.day() == 1)  && (currentTime.hour() <= 11)))
                {
-                       g_lamexp_app_icon.appIcon = new QIcon(":/MainIcon4.png");
+                       g_lamexp_icon_data.reset(new QIcon(":/MainIcon4.png"));
                }
                else if((currentDate.month() == 12) && (currentDate.day() >= 24) && (currentDate.day() <= 26))
                {
-                       g_lamexp_app_icon.appIcon = new QIcon(":/MainIcon3.png");
+                       g_lamexp_icon_data.reset(new QIcon(":/MainIcon3.png"));
                }
                else if(lamexp_computus(currentDate))
                {
-                       g_lamexp_app_icon.appIcon = new QIcon(":/MainIcon2.png");
+                       g_lamexp_icon_data.reset(new QIcon(":/MainIcon2.png"));
                }
                else
                {
-                       g_lamexp_app_icon.appIcon = new QIcon(":/MainIcon1.png");
+                       g_lamexp_icon_data.reset(new QIcon(":/MainIcon1.png"));
                }
        }
 
-       return *g_lamexp_app_icon.appIcon;
+       return *g_lamexp_icon_data;
 }
 
 /*
- * Broadcast event to all windows
+ * Version number to human-readable string
  */
-bool lamexp_broadcast(int eventType, bool onlyToVisible)
+const QString lamexp_version2string(const QString &pattern, unsigned int version, const QString &defaultText, const QString &tag)
 {
-       if(QApplication *app = dynamic_cast<QApplication*>(QApplication::instance()))
+       if(version == UINT_MAX)
        {
-               qDebug("Broadcasting %d", eventType);
-               
-               bool allOk = true;
-               QEvent poEvent(static_cast<QEvent::Type>(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;
+               return defaultText;
        }
-       else
+       
+       QString result = pattern;
+       const int digits = result.count(QChar(L'?'), Qt::CaseInsensitive);
+       
+       if(digits < 1)
        {
-               qWarning("Broadcast failed, could not get QApplication instance!");
-               return false;
+               return result;
+       }
+       
+       int pos = 0, index = -1;
+       const QString versionStr = QString().sprintf("%0*u", digits, version);
+       Q_ASSERT(versionStr.length() == digits);
+       
+       while((index = result.indexOf(QChar(L'?'), Qt::CaseInsensitive)) >= 0)
+       {
+               result[index] = versionStr[pos++];
        }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// INITIALIZATION
-///////////////////////////////////////////////////////////////////////////////
-
-extern "C" void _lamexp_global_init_utils(void)
-{
-       LAMEXP_ZERO_MEMORY(g_lamexp_temp_folder);
-       LAMEXP_ZERO_MEMORY(g_lamexp_app_icon);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// FINALIZATION
-///////////////////////////////////////////////////////////////////////////////
 
-extern "C" void _lamexp_global_free_utils(void)
-{
-       //Delete temporary files
-       const QString &tempFolder = lamexp_temp_folder2();
-       if(!tempFolder.isEmpty())
+       if(!tag.isEmpty())
        {
-               bool success = false;
-               for(int i = 0; i < 100; i++)
-               {
-                       if(lamexp_clean_folder(tempFolder))
-                       {
-                               success = true;
-                               break;
-                       }
-                       lamexp_sleep(100);
-               }
-               if(!success)
+               if((index = result.indexOf(QChar(L'#'), Qt::CaseInsensitive)) >= 0)
                {
-                       lamexp_system_message(L"Sorry, LameXP was unable to clean up all temporary files. Some residual files in your TEMP directory may require manual deletion!", lamexp_beep_warning);
-                       lamexp_exec_shell(NULL, tempFolder, QString(), QString(), true);
+                       result.remove(index, 1).insert(index, tag);
                }
        }
 
-       //Free memory
-       LAMEXP_DELETE(g_lamexp_temp_folder.path);
-       LAMEXP_DELETE(g_lamexp_app_icon.appIcon);
+       return result;
 }