diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp index adee2d6..f003403 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -30,7 +30,6 @@ std::string getPath(SettingsTargetDirectory target, bool create) { pathLen++; currentChar = roamingPath[pathLen]; } - settingsPath = (wchar_t*)calloc(pathLen + maxPathBypassLen + diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index 86c9a22..cecaf5a 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -941,6 +941,8 @@ HeaderWidget::HeaderWidget(QWidget *parent) : QWidget(parent) { } connect(channels, &QCheckBox::stateChanged, [this, parent](){ set->setValue("show_channels", channels->isChecked(), sizeof("show_channels")); + if(!OverseerHandler::settingsPath.empty()) + set->save(OverseerHandler::settingsPath.c_str()); if(parent) QCoreApplication::instance()->postEvent (parent, new QEvent((QEvent::Type)CustomQEvent::RecomposeMainWindow)); diff --git a/src/settings.cpp b/src/settings.cpp index 01b5114..3760983 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -3,14 +3,17 @@ namespace ini { - wchar_t* utf8toUtf16(const char* str) { + wchar_t* utf8toUtf16(const char* str, uint64_t* size = nullptr) { if(!str || str[0] == '\0') return nullptr; int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if(size) *size = sizeNeeded; wchar_t* utf16 = (wchar_t*)calloc(sizeNeeded, 1); MultiByteToWideChar(CP_UTF8, 0, str, -1, utf16, sizeNeeded); return utf16; } + + UserSettings::UserSettings(char* textContents) { //Parsing values bool isCRLF = false; @@ -47,7 +50,6 @@ namespace ini { free(textContents); } - //todo: buffer overflow. poc char* const UserSettings::getValue(char* key, uint64_t len) { if (auto search = values.find(key); search != values.end()) return (char* const) search->second; @@ -92,6 +94,80 @@ namespace ini { return; } + bool UserSettings::save(const char* path) { + wchar_t maxPathBypass[] = L"\\\\?\\"; + uint32_t maxPathBypassLen = (sizeof(maxPathBypass)/ sizeof(wchar_t)) - 1; + + if(!path) return false; + uint64_t convertedPathSize = 0; + wchar_t* convertedPath = utf8toUtf16(path, &convertedPathSize); + if(!convertedPath) return false; + wchar_t* utf16Path = (wchar_t*)calloc(maxPathBypassLen + convertedPathSize, sizeof(wchar_t)); + memcpy(utf16Path, maxPathBypass, sizeof(wchar_t) * maxPathBypassLen); + memcpy(utf16Path + maxPathBypassLen, convertedPath, sizeof(wchar_t) * convertedPathSize); + free(convertedPath); + + #define releaseBeforeReturn() do { \ + CloseHandle(settingsHandle); \ + settingsHandle = nullptr; \ + free(utf16Path); \ + free(text); \ + } while(0) + + //We initially reserve 1024B for flushing. If storage is exceeded, more same-size chunks are allocated + const uint64_t chunkSize = 1024; + char* text = (char*)calloc(chunkSize, sizeof(char)); + uint64_t mapSize = values.size(); + uint64_t chunks = 1; + uint64_t keySize = 0, valueSize = 0, totalSize = 0, previousStepSize = 0; + //for(std::pair entry : values) { + std::unordered_map::iterator it; + for (it = values.begin(); it != values.end(); it++) { + keySize = strlen(it->first); + valueSize = strlen(it->second); + totalSize += valueSize + keySize + (it == values.begin() ? 1 : 2); //newline and separator + + if(totalSize > (chunkSize * chunks)) { + text = (char*)realloc(text, (++chunks * chunkSize)); + } + + if(it != values.begin()) + memcpy(text + previousStepSize++, "\n", sizeof(char)); + memcpy(text + previousStepSize, it->first, sizeof(char) * keySize); + memcpy(text + previousStepSize + keySize, "=", sizeof(char)); + memcpy(text + previousStepSize + 1 + keySize, it->second, sizeof(char) * valueSize); + + previousStepSize = totalSize; + } + + HANDLE settingsHandle = nullptr; + settingsHandle = CreateFile2( + utf16Path, + GENERIC_READ | GENERIC_WRITE, + 0, + CREATE_ALWAYS, + NULL); + if(settingsHandle == INVALID_HANDLE_VALUE) { + releaseBeforeReturn(); + return false; + } + + DWORD bytesWritten; + BOOL writeSuccess = WriteFile( + settingsHandle, + text, + totalSize, + &bytesWritten, + nullptr + ); + + releaseBeforeReturn(); + if (writeSuccess == TRUE) return true; + else return false; + + return false; + } + UserSettings::~UserSettings() { //if(textContents) free(textContents); for(std::pair entry : values) { diff --git a/src/settings.h b/src/settings.h index e23a0a6..9974507 100644 --- a/src/settings.h +++ b/src/settings.h @@ -57,18 +57,13 @@ class UserSettings { char* const getValue(char* key, uint64_t len = 0); void setValue(char* key, char* value, uint64_t valueSize, uint64_t keySize); //'\0' included void setValue(char* key, bool value, uint64_t keySize); //'\0' included - //void setValue(char* key, uint64_t value, uint64_t valueSize, uint64_t keySize); //'\0' included - + + bool save(const char* path); protected: private: - //void* returnValue(); - UserSettings(char* text = nullptr); - - //std::map values{ {"show_channels", false}, {"test", 7} }; + UserSettings(char* text = nullptr); std::unordered_map values; - //char* textContents = nullptr; - //uint64_t textContentsSize = 0; char* pos = "true"; char* neg = "false"; };