From 1ae324b68a9f64c82d6408d6c6d2c1d523ff4071 Mon Sep 17 00:00:00 2001 From: Hane Date: Fri, 6 Dec 2024 17:55:46 +0100 Subject: [PATCH] wip: settings in effect --- src/back/backlasses.cpp | 90 +++++++++++++++ src/back/backlasses.h | 36 ++++++ src/cont/contclasses.cpp | 32 +++++- src/cont/contclasses.h | 9 +- src/global.h | 6 +- src/qtestmain.cpp | 11 +- src/settings.cpp | 242 +++++++++++++++------------------------ src/settings.h | 9 +- 8 files changed, 277 insertions(+), 158 deletions(-) diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp index e51c011..adee2d6 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -1,6 +1,96 @@ #include "backlasses.h" #include "backfuncs.h" +std::string getPath(SettingsTargetDirectory target, bool create) { + wchar_t* settingsPath = nullptr; + wchar_t settingsFile[] = L"\\settings.ini"; + uint32_t settingsFileLen = (sizeof(settingsFile) / sizeof(wchar_t)) - 1; + wchar_t maxPathBypass[] = L"\\\\?\\"; + uint32_t exePathLength = 0; + wchar_t folderPath[] = L"\\mixerq"; + uint32_t maxPathBypassLen = (sizeof(maxPathBypass)/ sizeof(wchar_t)) - 1; + uint32_t folderPathLen = (sizeof(folderPath) / sizeof(wchar_t)) - 1; + wchar_t* roamingPath = nullptr; + + log_wdebugcpp(L"Bypass size: " + std::to_wstring((sizeof(maxPathBypass)/sizeof(maxPathBypass[0])))); + + switch(target) { + case HOME_DIR: + { + if(SHGetKnownFolderPath( + FOLDERID_RoamingAppData, + 0, + NULL, + &roamingPath) + == S_OK) { + //Retrieve path len + uint32_t pathLen = 0; + wchar_t currentChar = roamingPath[pathLen]; + while(currentChar != '\0') { + pathLen++; + currentChar = roamingPath[pathLen]; + } + + + settingsPath = (wchar_t*)calloc(pathLen + + maxPathBypassLen + + folderPathLen + + settingsFileLen, + sizeof(wchar_t)); + memcpy(settingsPath, maxPathBypass, sizeof(wchar_t) * maxPathBypassLen); + memcpy(settingsPath + (maxPathBypassLen), roamingPath, sizeof(wchar_t) * pathLen); + CoTaskMemFree(roamingPath); + memcpy(settingsPath + (maxPathBypassLen + pathLen), + folderPath, sizeof(wchar_t) * folderPathLen); + log_wdebugcpp(L"Settings folder path: " + std::wstring(settingsPath)); + + if(CreateDirectoryW(settingsPath, NULL) || GetLastError() == ERROR_ALREADY_EXISTS) { + memcpy(settingsPath + (maxPathBypassLen + pathLen + folderPathLen), + settingsFile, sizeof(wchar_t) * settingsFileLen); + std::string utf8path = utf16ToUtf8(settingsPath); + free(settingsPath); + return utf8path; + } + } + } + return nullptr; + break; + case APP_PATH: + { + //Executable dir + settingsPath = (wchar_t*)calloc(UNICODE_STRING_MAX_CHARS, sizeof(wchar_t)); + exePathLength = GetModuleFileNameW( + NULL, + settingsPath, + UNICODE_STRING_MAX_CHARS + ); + //reverse wcsstr + while(exePathLength >= 0) { + if(settingsPath[exePathLength] == '\\') { + memset(settingsPath + exePathLength, + 0, + (UNICODE_STRING_MAX_CHARS - exePathLength) * sizeof(wchar_t)); + break; + } else exePathLength--; + } + log_wdebugcpp(L"Exe folder: " + std::wstring(settingsPath)); + if((UNICODE_STRING_MAX_CHARS - exePathLength) > (settingsFileLen + 1)) { + memcpy(settingsPath + exePathLength, settingsFile, sizeof(wchar_t) * settingsFileLen); + std::string utf8path = utf16ToUtf8(settingsPath); + free(settingsPath); + return utf8path; + } + } + return nullptr; + break; + default: + return nullptr; + break; + } + return nullptr; + +} + EndpointNewSessionCallback::EndpointNewSessionCallback(EndpointHandler* eph){ this->eph = eph; } diff --git a/src/back/backlasses.h b/src/back/backlasses.h index f5fba61..3a94707 100644 --- a/src/back/backlasses.h +++ b/src/back/backlasses.h @@ -7,6 +7,42 @@ class EndpointVolumeCallback; class Session; +std::string getPath(SettingsTargetDirectory target, bool create); + +// Convert a wide UTF16LE string to an UTF8 string +static inline std::string utf16ToUtf8(const wchar_t* wstr) { + if(!wstr || wstr[0] == '\0') return std::string(); + int size_needed = WideCharToMultiByte(CP_UTF8, + 0, + wstr, + -1, + NULL, + 0, + NULL, + NULL); + std::string str(size_needed, 0); + WideCharToMultiByte(CP_UTF8, + 0, + wstr, + -1, + &str[0], + size_needed, + NULL, + NULL); + return str; +} + +// Convert an UTF8 string to a wide UTF16LE String +/* + * std::wstring utf8_decode(const std::string &str) + * { + * if( str.empty() ) return std::wstring(); + * int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); + * std::wstring wstrTo( size_needed, 0 ); + * MultiByteToWideChar (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed); + * return wstrTo; + * } + */ class Endpoint { diff --git a/src/cont/contclasses.cpp b/src/cont/contclasses.cpp index 71f981d..c6a2149 100644 --- a/src/cont/contclasses.cpp +++ b/src/cont/contclasses.cpp @@ -1,6 +1,27 @@ #include "backlasses.h" #include "contclasses.h" -//TODO: pragma once + +void setConfigDirToDefaults() { + #define tryFileDir(dir, create) do { \ + OverseerHandler::settingsPath = getPath(dir, create); \ + set = ini::UserSettings::createSettings(OverseerHandler::settingsPath.c_str()); \ + if(set) { \ + return; \ + } else OverseerHandler::settingsPath.clear(); \ + } while(0) + #define tryOpenFileDir(dir) tryFileDir(dir, false) + #define tryCreateFileDir(dir) tryFileDir(dir, true) + + tryOpenFileDir(SettingsTargetDirectory::APP_PATH); + tryOpenFileDir(SettingsTargetDirectory::HOME_DIR); + tryCreateFileDir(SettingsTargetDirectory::HOME_DIR); + tryCreateFileDir(SettingsTargetDirectory::APP_PATH); + + return; + #undef tryOpenFileDir + #undef tryCreateFileDir + #undef tryFileDir +} EndpointHandler::EndpointHandler(uint64_t idx, Flows flow) { //std::vector endpoints = osh->getPlaybackEndpoints().at(idx); @@ -205,6 +226,14 @@ OverseerHandler::OverseerHandler() { this->os = new Overseer(); } +void OverseerHandler::setSettingsPath(std::string path) { + OverseerHandler::settingsPath = path; +} + +std::string OverseerHandler::getSettingsPath(){ + return OverseerHandler::settingsPath; +} + void OverseerHandler::populateSystemValues() { this->os->populateSystemValues(); } @@ -374,3 +403,4 @@ void OverseerHandler::setRemoveEndpointWidgetFunction(std::function ephs){ this->playbackEndpointHandlers = ephs; } + diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h index e3ebab6..0f5cedd 100644 --- a/src/cont/contclasses.h +++ b/src/cont/contclasses.h @@ -1,6 +1,7 @@ #pragma once #include "global.h" +#include "settings.h" #include "contsessionclasses.h" //#define invoke_mem_fn(object,ptrToMember) ((object).*(ptrToMember)) //#define pinvoke_mem_fn(object,ptrToMember) ((object)->*(ptrToMember)) @@ -16,11 +17,13 @@ struct BackEndpointVolumeCallbackInfo { NGuid caller; bool muted; float mainVolume; - size_t channels; + size_t channels; std::vector channelVolumes; bool updateName = false; }; +void setConfigDirToDefaults(); + class EndpointHandler { public: @@ -97,6 +100,9 @@ class OverseerHandler { public: OverseerHandler(); + static void setSettingsPath(std::string path); + static std::string getSettingsPath(); + static inline std::string settingsPath; void populateSystemValues(); void openControlPanel(); ProcessedNativeEvent processTopLevelWindowMessage(void* msg); @@ -143,6 +149,7 @@ private: /* Session's */ std::function changeSessionVolume; + //std::function updateFrontVolumeCallback; //std::function updateFrontMuteCallback; diff --git a/src/global.h b/src/global.h index 10f45ab..7c02902 100644 --- a/src/global.h +++ b/src/global.h @@ -41,7 +41,11 @@ //INIT BACK - +enum SettingsTargetDirectory { + HOME_DIR = 0, + APP_PATH = (1 << 0), + CUSTOM = (1 << 1), +}; enum ProcessedNativeEvent { NONE = 0, diff --git a/src/qtestmain.cpp b/src/qtestmain.cpp index e367ae9..8b34385 100644 --- a/src/qtestmain.cpp +++ b/src/qtestmain.cpp @@ -4,7 +4,6 @@ #include "qtclasses.h" #include "qtvisuals.h" #include "settings.h" -//#include "global.h" OverseerHandler *osh = nullptr; ini::UserSettings *set = nullptr; @@ -56,8 +55,14 @@ int main (int argc, char* argv[]) { * log_debugcpp(a.toStdString()); * } */ - //std::map* values = new std::map{ {"show_channels", false}, {"test", 7} }; - set = new ini::UserSettings(parseCmdArgs(argc, argv)); + char* userSettingsPath = parseCmdArgs(argc, argv); + if (userSettingsPath) + set = ini::UserSettings::createSettings(userSettingsPath, true); + + if (set) + OverseerHandler::settingsPath = std::string(userSettingsPath); + else setConfigDirToDefaults(); + initialize_file_log(); atexit(closeDebugFileLog); diff --git a/src/settings.cpp b/src/settings.cpp index 0ced9fd..01b5114 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -3,100 +3,48 @@ namespace ini { - UserSettings::UserSettings(char* path) { - wchar_t* settingsPath = nullptr; - wchar_t settingsFile[] = L"\\settings.ini"; - uint32_t settingsFileLen = (sizeof(settingsFile) / sizeof(wchar_t)) - 1; - wchar_t maxPathBypass[] = L"\\\\?\\"; - log_wdebugcpp(L"Bypass size: " + std::to_wstring((sizeof(maxPathBypass)/sizeof(maxPathBypass[0])))); + wchar_t* utf8toUtf16(const char* str) { + if(!str || str[0] == '\0') return nullptr; + int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + wchar_t* utf16 = (wchar_t*)calloc(sizeNeeded, 1); + MultiByteToWideChar(CP_UTF8, 0, str, -1, utf16, sizeNeeded); + return utf16; + } - //Executable dir - settingsPath = (wchar_t*)calloc(UNICODE_STRING_MAX_CHARS, sizeof(wchar_t)); - uint32_t exePathLength = GetModuleFileNameW( - NULL, - settingsPath, - UNICODE_STRING_MAX_CHARS - ); - //reverse wcsstr - while(exePathLength >= 0) { - if(settingsPath[exePathLength] == '\\') { - memset(settingsPath + exePathLength, - 0, - (UNICODE_STRING_MAX_CHARS - exePathLength) * sizeof(wchar_t)); - break; - } else exePathLength--; - } - log_wdebugcpp(L"Exe folder: " + std::wstring(settingsPath)); + UserSettings::UserSettings(char* textContents) { + //Parsing values + bool isCRLF = false; + char *curLine = textContents; + char *separator = nullptr, *key = nullptr, *value = nullptr; + while(curLine) { + char* nextLine = strchr(curLine, '\n'); + if(nextLine == curLine + 1 || nextLine == curLine + 2) + goto nextIteration; + if (nextLine && (isCRLF || *(nextLine - 1) == '\r')) { + isCRLF = true; + *(nextLine - 1) = '\0'; + } else if (nextLine) *nextLine = '\0'; // temporarily terminate the current line + log_debugcpp("curLine: " + std::string(curLine) + " "); - HANDLE settingsHandle = nullptr; - if((UNICODE_STRING_MAX_CHARS - exePathLength) > (settingsFileLen + 1)) { - memcpy(settingsPath + exePathLength, settingsFile, sizeof(wchar_t) * settingsFileLen); - settingsHandle = CreateFile2( - settingsPath, - GENERIC_READ | GENERIC_WRITE, - 0, - OPEN_ALWAYS, - NULL); - if(settingsHandle != INVALID_HANDLE_VALUE) { log_debugcpp("Filecreated!"); } - else { CloseHandle(settingsHandle); settingsHandle = nullptr; return; } - } + separator = strchr(curLine, '='); + if(!separator) + goto nextIteration; + *separator = '\0'; + key = trimAndAllocate(curLine); + value = trimAndAllocate(separator + 1); + values.try_emplace(key, value); + log_debugcpp("ini Map size: " + std::to_string(values.size())); + *separator = '='; - //Calculating file size and reading file - if(settingsHandle) { - uint64_t fileSize; - LARGE_INTEGER fileSizeStruct; - if(!GetFileSizeEx(settingsHandle, &fileSizeStruct)) return; - fileSize = fileSizeStruct.QuadPart; - - uint32_t bytesRead = 0; - textContentsSize = fileSize + 1; - textContents = (char*)calloc(textContentsSize, sizeof(char)); - if (ReadFile(settingsHandle, textContents, fileSize, - (LPDWORD)&bytesRead, NULL) != TRUE) { - free(textContents); - return; + nextIteration: + if (nextLine) { // then restore newline-char, just to be tidy + if (isCRLF) + *(nextLine - 1) = '\r'; + else *nextLine = '\n'; } - //textContents.assign(tempTextContents); - //free(tempTextContents); - - //Parsing values - bool isCRLF = false; - char *curLine = textContents; - char *separator = nullptr, *key = nullptr, *value = nullptr; - while(curLine) { - char* nextLine = strchr(curLine, '\n'); - if(nextLine == curLine + 1 || nextLine == curLine + 2) goto nextIteration; - if (nextLine && (isCRLF || *(nextLine - 1) == '\r')) { - isCRLF = true; - *(nextLine - 1) = '\0'; - } else if (nextLine) *nextLine = '\0'; // temporarily terminate the current line - log_debugcpp("curLine: " + std::string(curLine) + " "); - - separator = strchr(curLine, '='); - if(!separator) goto nextIteration; - *separator = '\0'; - key = trimAndAllocate(curLine); - value = trimAndAllocate(separator + 1); - values.try_emplace(key, value); - log_debugcpp("ini Map size: " + std::to_string(values.size())); - *separator = '='; - - nextIteration: - if (nextLine) { // then restore newline-char, just to be tidy - if (isCRLF) - *(nextLine - 1) = '\r'; - else *nextLine = '\n'; - } - curLine = nextLine ? (nextLine + 1) : NULL; - } - /* - * for(const std::pair keyVal : defaultValues) { - * if (textContents.find(keyVal.first) { - * if (keyVal. - * } - * } - */ + curLine = nextLine ? (nextLine + 1) : NULL; } + free(textContents); } //todo: buffer overflow. poc @@ -139,70 +87,68 @@ namespace ini { return; } - newKey = (char*)calloc(keySize, sizeof(char)); + newKey = (char*)calloc(keySize, sizeof(char)); values.insert(std::make_pair(newKey, value ? pos : neg)); return; } - - - //AppData path - /* - * wchar_t folderPath[] = L"\\mixerq"; - * - * wchar_t* roamingPath = nullptr; - * if(SHGetKnownFolderPath( - * FOLDERID_RoamingAppData, - * 0, - * NULL, - * &roamingPath) - * == S_OK) { - * uint32_t pathLen = 0; - * wchar_t currentChar = roamingPath[pathLen]; - * while(currentChar != '\0') { - * pathLen++; - * currentChar = roamingPath[pathLen]; - * } - * - * uint32_t maxPathBypassLen = (sizeof(maxPathBypass)/ sizeof(wchar_t)) - 1; - * uint32_t folderPathLen = (sizeof(folderPath) / sizeof(wchar_t)) - 1; - * settingsPath = (wchar_t*)calloc(pathLen + - * maxPathBypassLen + - * folderPathLen + - * settingsFileLen, - * sizeof(wchar_t)); - * memcpy(settingsPath, maxPathBypass, sizeof(wchar_t) * maxPathBypassLen); - * memcpy(settingsPath + (maxPathBypassLen), roamingPath, sizeof(wchar_t) * pathLen); - * CoTaskMemFree(roamingPath); - * memcpy(settingsPath + (maxPathBypassLen + pathLen), - * folderPath, sizeof(wchar_t) * folderPathLen); - * log_wdebugcpp(L"Settings folder path: " + std::wstring(settingsPath)); - * - * if(CreateDirectoryW(settingsPath, NULL) || GetLastError() == ERROR_ALREADY_EXISTS) { - * memcpy(settingsPath + (maxPathBypassLen + pathLen + folderPathLen), - * settingsFile, sizeof(wchar_t) * settingsFileLen); - * - * HANDLE settingsHandle = CreateFile2( - * settingsPath, - * GENERIC_READ | GENERIC_WRITE, - * 0, - * OPEN_ALWAYS, - * NULL); - * if(settingsHandle != INVALID_HANDLE_VALUE) log_debugcpp("Filecreated!"); - * - * } - * //End AppData - */ - + UserSettings::~UserSettings() { + //if(textContents) free(textContents); + for(std::pair entry : values) { + free(entry.first); + if (!(entry.second == pos || entry.second == neg)) + free(entry.second); + } + } - -UserSettings::~UserSettings() { - if(textContents) free(textContents); - for(std::pair entry : values) { - free(entry.first); - free(entry.second); + UserSettings* UserSettings::createSettings(const char* path, bool create) { + if(!path) return nullptr; + wchar_t* utf16Path = utf8toUtf16(path); + if(!utf16Path) return nullptr; + + #define releaseBeforeReturn() do { \ + CloseHandle(settingsHandle); \ + settingsHandle = nullptr; \ + free(utf16Path); \ + } while(0) + + char* textContents; + HANDLE settingsHandle = nullptr; + settingsHandle = CreateFile2( + utf16Path, + GENERIC_READ | GENERIC_WRITE, + 0, + (create ? OPEN_ALWAYS : OPEN_EXISTING), + NULL); + if(settingsHandle == INVALID_HANDLE_VALUE) { + releaseBeforeReturn(); + return nullptr; + } + + //Calculating file size and reading file + uint64_t fileSize; + LARGE_INTEGER fileSizeStruct; + if(!GetFileSizeEx(settingsHandle, &fileSizeStruct)) { + releaseBeforeReturn(); + return nullptr; + } + fileSize = fileSizeStruct.QuadPart; + + uint32_t bytesRead = 0; + uint64_t textContentsSize = fileSize + 1; + textContents = (char*)calloc(textContentsSize, sizeof(char)); + if (ReadFile(settingsHandle, textContents, fileSize, + (LPDWORD)&bytesRead, NULL) != TRUE) { + releaseBeforeReturn(); + return nullptr; + } + + releaseBeforeReturn(); + return new UserSettings(textContents); + + //textContents.assign(tempTextContents); + //free(tempTextContents); + #undef releaseBeforeReturn } -} - } diff --git a/src/settings.h b/src/settings.h index 2e88598..e23a0a6 100644 --- a/src/settings.h +++ b/src/settings.h @@ -2,7 +2,7 @@ #include "global.h" namespace ini { - + //Trims spaces, LF and CRLF static inline char* trimAndAllocate(const char* in, uint64_t len = 0) { if (!in) return nullptr; @@ -51,7 +51,7 @@ namespace ini { class UserSettings { public: - UserSettings(char* path = nullptr); + static UserSettings* createSettings(const char* path = nullptr, bool create = false); ~UserSettings(); char* const getValue(char* key, uint64_t len = 0); @@ -63,11 +63,12 @@ class UserSettings { private: //void* returnValue(); + UserSettings(char* text = nullptr); //std::map values{ {"show_channels", false}, {"test", 7} }; std::unordered_map values; - char* textContents = nullptr; - uint64_t textContentsSize = 0; + //char* textContents = nullptr; + //uint64_t textContentsSize = 0; char* pos = "true"; char* neg = "false"; };