527 lines
14 KiB
C++
527 lines
14 KiB
C++
#include "stdafx.h"
|
|
#include "Common.h"
|
|
|
|
#ifdef USE_OPENSSL
|
|
#include <openssl/rand.h>
|
|
#endif
|
|
|
|
#ifndef WIN32 // vswprintf
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
|
|
int vswprintf_l(wchar_t * _String, size_t _Count, const wchar_t * _Format, va_list _Ap)
|
|
{
|
|
wchar_t _Format_l[1025];
|
|
ASSERT(wcslen(_Format) < 1024);
|
|
wcscpy(_Format_l, _Format);
|
|
|
|
for(int i=0; i<wcslen(_Format_l); i++)
|
|
{
|
|
if(_Format_l[i] == L'%')
|
|
{
|
|
switch(_Format_l[i+1])
|
|
{
|
|
case L's': _Format_l[i+1] = 'S'; break;
|
|
case L'S': _Format_l[i+1] = 's'; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return vswprintf(_String, _Count, _Format_l, _Ap);
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Time Functions
|
|
//
|
|
|
|
time_t GetTime()
|
|
{
|
|
QDateTime dateTime = QDateTime::currentDateTime();
|
|
time_t time = dateTime.toTime_t(); // returns time in seconds (since 1970-01-01T00:00:00) in UTC !
|
|
return time;
|
|
}
|
|
|
|
struct SCurTick
|
|
{
|
|
SCurTick() {Timer.start();}
|
|
quint64 Get(){return Timer.elapsed();}
|
|
QElapsedTimer Timer;
|
|
} g_CurTick;
|
|
|
|
quint64 GetCurTick()
|
|
{
|
|
return g_CurTick.Get();
|
|
}
|
|
|
|
QString UnEscape(QString Text)
|
|
{
|
|
QString Value;
|
|
bool bEsc = false;
|
|
for(int i = 0; i < Text.size(); i++)
|
|
{
|
|
QChar Char = Text.at(i);
|
|
if(bEsc)
|
|
{
|
|
switch(Char.unicode())
|
|
{
|
|
case L'\\': Value += L'\\'; break;
|
|
case L'\'': Value += L'\''; break;
|
|
case L'\"': Value += L'\"'; break;
|
|
case L'a': Value += L'\a'; break;
|
|
case L'b': Value += L'\b'; break;
|
|
case L'f': Value += L'\f'; break;
|
|
case L'n': Value += L'\n'; break;
|
|
case L'r': Value += L'\r'; break;
|
|
case L't': Value += L'\t'; break;
|
|
case L'v': Value += L'\v'; break;
|
|
default: Value += Char.unicode();break;
|
|
}
|
|
bEsc = false;
|
|
}
|
|
else if(Char == L'\\')
|
|
bEsc = true;
|
|
else
|
|
Value += Char;
|
|
}
|
|
return Value;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Other Functions
|
|
//
|
|
|
|
quint64 GetRand64()
|
|
{
|
|
quint64 Rand64;
|
|
#ifdef USE_OPENSSL
|
|
int Ret = RAND_bytes((byte*)&Rand64, sizeof(quint64));
|
|
ASSERT(Ret == 1); // An error occurs if the PRNG has not been seeded with enough randomness to ensure an unpredictable byte sequence.
|
|
#else
|
|
//CryptoPP::AutoSeededRandomPool rng;
|
|
//rng.GenerateBlock((byte*)&Rand64, sizeof(quint64));
|
|
|
|
Rand64 = QRandomGenerator::system()->generate64();
|
|
#endif
|
|
return Rand64;
|
|
}
|
|
|
|
QString GetRand64Str(bool forUrl)
|
|
{
|
|
quint64 Rand64 = GetRand64();
|
|
QString sRand64 = QByteArray((char*)&Rand64,sizeof(quint64)).toBase64();
|
|
if(forUrl)
|
|
sRand64.replace("+","-").replace("/","_");
|
|
return sRand64.replace("=","");
|
|
}
|
|
|
|
|
|
int GetRandomInt(int iMin, int iMax)
|
|
{
|
|
return QRandomGenerator::system()->bounded(iMin, iMax);
|
|
}
|
|
|
|
StrPair Split2(const QString& String, QString Separator, bool Back)
|
|
{
|
|
int Sep = Back ? String.lastIndexOf(Separator) : String.indexOf(Separator);
|
|
if(Sep != -1)
|
|
return qMakePair(String.left(Sep).trimmed(), String.mid(Sep+Separator.length()).trimmed());
|
|
return qMakePair(String.trimmed(), QString());
|
|
}
|
|
|
|
QStringList SplitStr(const QString& String, QString Separator)
|
|
{
|
|
QStringList List = String.split(Separator);
|
|
for(int i=0; i < List.count(); i++)
|
|
{
|
|
List[i] = List[i].trimmed();
|
|
if(List[i].isEmpty())
|
|
List.removeAt(i--);
|
|
}
|
|
return List;
|
|
}
|
|
|
|
TArguments GetArguments(const QString& Arguments, QChar Separator, QChar Assigner, QString* First, bool bLowerKeys, bool bReadEsc)
|
|
{
|
|
TArguments ArgumentList;
|
|
|
|
bool bReadValue = false;
|
|
QString Name;
|
|
QString Value;
|
|
QChar Prime = L'\0';
|
|
bool bEsc = false;
|
|
for(int i = 0; i < Arguments.size(); i++)
|
|
{
|
|
QChar Char = Arguments.at(i);
|
|
|
|
if(Prime != L'\0') // inside a string
|
|
{
|
|
if(bEsc) // ESC sequence handling
|
|
{
|
|
switch(Char.unicode())
|
|
{
|
|
case L'\\': Value += L'\\'; break;
|
|
case L'\'': Value += L'\''; break;
|
|
case L'\"': Value += L'\"'; break;
|
|
case L'a': Value += L'\a'; break;
|
|
case L'b': Value += L'\b'; break;
|
|
case L'f': Value += L'\f'; break;
|
|
case L'n': Value += L'\n'; break;
|
|
case L'r': Value += L'\r'; break;
|
|
case L't': Value += L'\t'; break;
|
|
case L'v': Value += L'\v'; break;
|
|
default: Value += L'?'; break;
|
|
}
|
|
bEsc = false;
|
|
}
|
|
else if(bReadEsc && Char == L'\\')
|
|
bEsc = true;
|
|
else if(Char == Prime) // end of the string
|
|
Prime = L'\0';
|
|
else
|
|
{
|
|
if(bReadValue)
|
|
Value += Char;
|
|
else
|
|
Name += Char;
|
|
}
|
|
continue;
|
|
}
|
|
else if(Char == L'"' || Char == L'\'') // begin of a string
|
|
{
|
|
Prime = Char;
|
|
continue;
|
|
}
|
|
|
|
if(/*Char == L' ' ||*/ Char == L'\t')
|
|
continue;
|
|
|
|
if(!bReadValue) // reading argument name, or value for default argument
|
|
{
|
|
if(Char == Separator)
|
|
{
|
|
if(First) {*First = Name; First = NULL;}
|
|
else ArgumentList.insertMulti("",Name.trimmed());
|
|
Name.clear();
|
|
}
|
|
else if(Char == Assigner)
|
|
bReadValue = true;
|
|
else
|
|
Name += Char;
|
|
}
|
|
else
|
|
{
|
|
if(Char == Separator)
|
|
{
|
|
if (bLowerKeys) Name = Name.toLower();
|
|
ArgumentList.insertMulti(Name.trimmed(),Value.trimmed());
|
|
//if(First) {*First = Name; First = NULL;}
|
|
Name.clear();
|
|
Value.clear();
|
|
bReadValue = false;
|
|
}
|
|
else
|
|
Value += Char;
|
|
}
|
|
}
|
|
|
|
if(!Name.isEmpty())
|
|
{
|
|
if(bReadValue)
|
|
{
|
|
if (bLowerKeys) Name = Name.toLower();
|
|
ArgumentList.insertMulti(Name.trimmed(),Value.trimmed());
|
|
//if (First) { *First = Name; }
|
|
}
|
|
else
|
|
{
|
|
if (First) { *First = Name; }
|
|
else ArgumentList.insertMulti("", Name.trimmed());
|
|
}
|
|
}
|
|
|
|
return ArgumentList;
|
|
}
|
|
|
|
QString FormatSize(quint64 Size, int Precision)
|
|
{
|
|
double Div;
|
|
if(Size > (quint64)(Div = 1.0*1024*1024*1024*1024*1024*1024))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " EB";
|
|
if(Size > (quint64)(Div = 1.0*1024*1024*1024*1024*1024))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " PB";
|
|
if(Size > (quint64)(Div = 1.0*1024*1024*1024*1024))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " TB";
|
|
if(Size > (quint64)(Div = 1.0*1024*1024*1024))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " GB";
|
|
if(Size > (quint64)(Div = 1.0*1024*1024))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " MB";
|
|
if(Size > (quint64)(Div = 1.0*1024))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " KB";
|
|
return QString::number(double(Size)) + "B";
|
|
}
|
|
|
|
QString FormatRate(quint64 Size, int Precision)
|
|
{
|
|
return FormatSize(Size, Precision) + "/s";
|
|
}
|
|
|
|
QString FormatUnit(quint64 Size, int Precision)
|
|
{
|
|
double Div;
|
|
if(Size > (quint64)(Div = 1.0*1000*1000*1000*1000*1000*1000))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " E";
|
|
if(Size > (quint64)(Div = 1.0*1000*1000*1000*1000*1000))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " P";
|
|
if(Size > (quint64)(Div = 1.0*1000*1000*1000*1000))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " T";
|
|
if(Size > (quint64)(Div = 1.0*1000*1000*1000))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " G";
|
|
if(Size > (quint64)(Div = 1.0*1000*1000))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " M";
|
|
if(Size > (quint64)(Div = 1.0*1000))
|
|
return QString::number(double(Size)/Div, 'f', Precision) + " K";
|
|
return QString::number(double(Size));
|
|
}
|
|
|
|
|
|
QString FormatTime(quint64 Time, bool ms)
|
|
{
|
|
int miliseconds = 0;
|
|
if (ms) {
|
|
miliseconds = Time % 1000;
|
|
Time /= 1000;
|
|
}
|
|
int seconds = Time % 60;
|
|
Time /= 60;
|
|
int minutes = Time % 60;
|
|
Time /= 60;
|
|
int hours = Time % 24;
|
|
int days = Time / 24;
|
|
if(ms && (minutes == 0) && (hours == 0) && (days == 0))
|
|
return QString().sprintf("%02d.%04d", seconds, miliseconds);
|
|
if((hours == 0) && (days == 0))
|
|
return QString().sprintf("%02d:%02d", minutes, seconds);
|
|
if (days == 0)
|
|
return QString().sprintf("%02d:%02d:%02d", hours, minutes, seconds);
|
|
return QString().sprintf("%dd%02d:%02d:%02d", days, hours, minutes, seconds);
|
|
}
|
|
|
|
QString FormatNumber(quint64 Number)
|
|
{
|
|
QString String = QString::number(Number);
|
|
for (int i = String.length() - 3; i > 0; i -= 3)
|
|
String.insert(i, QString::fromWCharArray(L"\u202F")); // L"\u2009"
|
|
return String;
|
|
}
|
|
|
|
QString FormatAddress(quint64 Address, int length)
|
|
{
|
|
return "0x" + QString::number(Address, 16).rightJustified(length, '0');
|
|
}
|
|
|
|
bool ReadFromDevice(QIODevice* dev, char* data, int len, int timeout)
|
|
{
|
|
while (dev->bytesAvailable() < len) {
|
|
if (!dev->waitForReadyRead(timeout))
|
|
return false;
|
|
}
|
|
return dev->read(data, len) == len;
|
|
}
|
|
|
|
uint8_t clamp(float v) //define a function to bound and round the input float value to 0-255
|
|
{
|
|
if (v < 0)
|
|
return 0;
|
|
if (v > 255)
|
|
return 255;
|
|
return (uint8_t)v;
|
|
}
|
|
|
|
// http://beesbuzz.biz/code/16-hsv-color-transforms
|
|
QRgb change_hsv_c(QRgb rgb, float fHue, float fSat, float fVal)
|
|
{
|
|
float in_r = qRed(rgb);
|
|
float in_g = qGreen(rgb);
|
|
float in_b = qBlue(rgb);
|
|
|
|
const float cosA = fSat*cos(fHue*3.14159265f/180); //convert degrees to radians
|
|
const float sinA = fSat*sin(fHue*3.14159265f/180); //convert degrees to radians
|
|
|
|
//helpers for faster calc //first 2 could actually be precomputed
|
|
const float aThird = 1.0f/3.0f;
|
|
const float rootThird = sqrtf(aThird);
|
|
const float oneMinusCosA = (1.0f - cosA);
|
|
const float aThirdOfOneMinusCosA = aThird * oneMinusCosA;
|
|
const float rootThirdTimesSinA = rootThird * sinA;
|
|
const float plus = aThirdOfOneMinusCosA +rootThirdTimesSinA;
|
|
const float minus = aThirdOfOneMinusCosA -rootThirdTimesSinA;
|
|
|
|
//calculate the rotation matrix
|
|
float matrix[3][3] = {
|
|
{ cosA + oneMinusCosA / 3.0f , minus , plus },
|
|
{ plus , cosA + aThirdOfOneMinusCosA , minus },
|
|
{ minus , plus , cosA + aThirdOfOneMinusCosA }
|
|
};
|
|
|
|
//Use the rotation matrix to convert the RGB directly
|
|
float out_r = clamp((in_r*matrix[0][0] + in_g*matrix[0][1] + in_b*matrix[0][2])*fVal);
|
|
float out_g = clamp((in_r*matrix[1][0] + in_g*matrix[1][1] + in_b*matrix[1][2])*fVal);
|
|
float out_b = clamp((in_r*matrix[2][0] + in_g*matrix[2][1] + in_b*matrix[2][2])*fVal);
|
|
return qRgb(out_r, out_g, out_b);
|
|
}
|
|
|
|
void GrayScale (QImage& Image)
|
|
{
|
|
if (Image.depth () == 32)
|
|
{
|
|
uchar* r = (Image.bits ());
|
|
uchar* g = (Image.bits () + 1);
|
|
uchar* b = (Image.bits () + 2);
|
|
|
|
uchar* end = (Image.bits() + Image.byteCount ());
|
|
while (r != end)
|
|
{
|
|
*r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3
|
|
|
|
r += 4;
|
|
g += 4;
|
|
b += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < Image.colorCount (); i++)
|
|
{
|
|
uint r = qRed (Image.color (i));
|
|
uint g = qGreen (Image.color (i));
|
|
uint b = qBlue (Image.color (i));
|
|
|
|
uint gray = (((r + g) >> 1) + b) >> 1;
|
|
|
|
Image.setColor (i, qRgba (gray, gray, gray, qAlpha (Image.color (i))));
|
|
}
|
|
}
|
|
}
|
|
|
|
QIcon MakeNormalAndGrayIcon(QIcon Icon)
|
|
{
|
|
QImage Image = Icon.pixmap(Icon.availableSizes().first()).toImage();
|
|
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Normal);
|
|
GrayScale(Image);
|
|
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Disabled);
|
|
return Icon;
|
|
}
|
|
|
|
QIcon MakeActionIcon(const QString& IconFile)
|
|
{
|
|
QImage Image(IconFile);
|
|
QIcon Icon;
|
|
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Normal);
|
|
GrayScale(Image);
|
|
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Disabled);
|
|
return Icon;
|
|
}
|
|
|
|
QAction* MakeAction(QToolBar* pParent, const QString& IconFile, const QString& Text)
|
|
{
|
|
QAction* pAction = new QAction(Text, pParent);
|
|
pAction->setIcon(MakeActionIcon(IconFile));
|
|
pParent->addAction(pAction);
|
|
return pAction;
|
|
}
|
|
|
|
QMenu* MakeMenu(QMenu* pParent, const QString& Text, const QString& IconFile)
|
|
{
|
|
if(!IconFile.isEmpty())
|
|
{
|
|
QImage Image(IconFile);
|
|
QIcon Icon;
|
|
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Normal);
|
|
GrayScale(Image);
|
|
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Disabled);
|
|
return pParent->addMenu(Icon, Text);
|
|
}
|
|
return pParent->addMenu(Text);
|
|
}
|
|
|
|
QAction* MakeAction(QMenu* pParent, const QString& Text, const QString& IconFile)
|
|
{
|
|
QAction* pAction = new QAction(Text, pParent);
|
|
if(!IconFile.isEmpty())
|
|
{
|
|
QImage Image(IconFile);
|
|
QIcon Icon;
|
|
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Normal);
|
|
GrayScale(Image);
|
|
Icon.addPixmap(QPixmap::fromImage(Image), QIcon::Disabled);
|
|
pAction->setIcon(Icon);
|
|
}
|
|
pParent->addAction(pAction);
|
|
return pAction;
|
|
}
|
|
|
|
QAction* MakeAction(QActionGroup* pGroup, QMenu* pParent, const QString& Text, const QVariant& Data)
|
|
{
|
|
QAction* pAction = new QAction(Text, pParent);
|
|
pAction->setCheckable(true);
|
|
pAction->setData(Data);
|
|
pAction->setActionGroup(pGroup);
|
|
pParent->addAction(pAction);
|
|
return pAction;
|
|
}
|
|
|
|
void SetPaleteTexture(QPalette& palette, QPalette::ColorRole role, const QImage& image)
|
|
{
|
|
for (int i = 0; i < QPalette::NColorGroups; ++i) {
|
|
QBrush brush(image);
|
|
brush.setColor(palette.brush(QPalette::ColorGroup(i), role).color());
|
|
palette.setBrush(QPalette::ColorGroup(i), role, brush);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
|
|
bool InitConsole(bool bCreateIfNeeded)
|
|
{
|
|
if (AttachConsole(ATTACH_PARENT_PROCESS) == FALSE)
|
|
{
|
|
if (!bCreateIfNeeded)
|
|
return false;
|
|
AllocConsole();
|
|
}
|
|
freopen("CONOUT$", "w", stdout);
|
|
printf("\r\n");
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// avoid flashing a bright white window when in dark mode
|
|
//
|
|
|
|
void SafeShow(QWidget* pWidget) {
|
|
static bool Lock = false;
|
|
pWidget->setProperty("windowOpacity", 0.0);
|
|
if (Lock == false) {
|
|
Lock = true;
|
|
pWidget->show();
|
|
QApplication::processEvents(QEventLoop::ExcludeSocketNotifiers | QEventLoop::ExcludeSocketNotifiers);
|
|
Lock = false;
|
|
} else
|
|
pWidget->show();
|
|
pWidget->setProperty("windowOpacity", 1.0);
|
|
}
|
|
|
|
int SafeExec(QDialog* pDialog){
|
|
SafeShow(pDialog);
|
|
return pDialog->exec();
|
|
} |