Loading backends/regedit/regedit.cpp +177 −138 Original line number Diff line number Diff line Loading @@ -32,61 +32,57 @@ #include <iostream> #include <string> #include <sstream> #include <algorithm> // Für std::replace #include <stdexcept> #include <memory> // Für std::unique_ptr // Spezifische Windows API Includes #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winreg.h> namespace confplus { /******************************************************************************* * Copyright (c) 2025, Jan Koester jan.koester@gmx.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ // Konfigurierbare Basis-HKEY. HKEY REGISTRY_ROOT_KEY = HKEY_CURRENT_USER; #include "regedit.h" #include "exception.h" // Angenommen: Hier ist ConfException definiert // ------------------------------------------------------------------------- // HILFSFUNKTIONEN // ------------------------------------------------------------------------- #include <iostream> #include <string> #include <sstream> #include <stdexcept> #include <algorithm> /** * @brief Splittet den Config-Pfad (/Abschnitt/Key) in den Registry Subkey-Pfad (Abschnitt\Key) * und den letzten Teil als Value-Namen. */ void splitConfigPath(const std::string& configPath, std::string& registryKeyPath, std::string& valueName) { // Entferne den führenden '/' std::string path = configPath.length() > 0 && configPath[0] == '/' ? configPath.substr(1) : configPath; // Spezifische Windows API Includes #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winreg.h> // Finde den letzten '/' size_t last_slash = path.rfind('/'); if (last_slash == std::string::npos) { registryKeyPath = ""; valueName = path; } else { registryKeyPath = path.substr(0, last_slash); valueName = path.substr(last_slash + 1); // Ersetze '/' durch '\' für die Registry-API std::replace(registryKeyPath.begin(), registryKeyPath.end(), '/', '\\'); } } bool isInteger(const std::string& s) { if (s.empty()) return false; std::string::const_iterator it = s.begin(); if (*it == '-' || *it == '+') it++; while (it != s.end() && std::isdigit(*it)) ++it; return it == s.end(); } namespace confplus { /** * @brief Rekursive Funktion zum Laden von Werten und Subkeys aus der Registry. * @param conf Das Config-Objekt, das gefüllt wird. * @param hKey Das Handle des aktuell geöffneten Registry-Schlüssels. * @param currentConfigPath Der aktuelle Pfad im Config-Objekt (z.B. "/HTTP"). */ void loadKeyRecursiveA(Config* conf, HKEY hKey, const std::string& currentConfigPath) { Loading @@ -101,77 +97,86 @@ namespace confplus { ); if (lRes != ERROR_SUCCESS) { // Fehler beim Abfragen ist nicht kritisch, einfach zurückkehren return; } // --- 2. Werte (Values) laden (z.B. PORT unter /HTTP) --- // --- 2. Werte (Values) laden --- if (dwValues > 0) { // Puffer allozieren (+1 für Nullterminierung) char* valueNameBuffer = new char[dwMaxValueNameLen + 1]; char* dataBuffer = new char[dwMaxValueLen + 1]; // maxNameSize und maxDataSize müssen die Nullterminierung mit einbeziehen DWORD maxNameSize = dwMaxValueNameLen > 0 ? dwMaxValueNameLen + 1 : 1; DWORD maxDataSize = dwMaxValueLen > 0 ? dwMaxValueLen + 1 : 1; // Verwendung von std::unique_ptr für automatische Speicherverwaltung std::unique_ptr<char[]> valueNameBuffer(new char[maxNameSize]); std::unique_ptr<char[]> dataBuffer(new char[maxDataSize]); DWORD dwSizeValueName, dwSizeData, dwType; for (DWORD i = 0; i < dwValues; ++i) { dwType = 0; dwSizeValueName = dwMaxValueNameLen + 1; dwSizeData = dwMaxValueLen + 1; dwSizeValueName = maxNameSize; dwSizeData = maxDataSize; lRes = RegEnumValueA( hKey, i, valueNameBuffer, &dwSizeValueName, valueNameBuffer.get(), &dwSizeValueName, NULL, &dwType, (LPBYTE)dataBuffer, &dwSizeData (LPBYTE)dataBuffer.get(), &dwSizeData ); if (lRes == ERROR_SUCCESS) { // Konstruiere den vollen Konfigurationspfad: /AktuellerPfad/ValueName std::string cname = currentConfigPath + "/" + std::string(valueNameBuffer); std::string valueNameStr = std::string(valueNameBuffer.get()); // Überspringe den '(Standardwert)', wenn benannte Werte vorhanden sind if (valueNameStr.empty() && dwValues > 1) { continue; } std::string cname = currentConfigPath + (valueNameStr.empty() ? "" : "/" + valueNameStr); std::string cvalue; if (dwType == REG_SZ) { cvalue = std::string(dataBuffer); cvalue = std::string(dataBuffer.get()); } else if (dwType == REG_DWORD) { std::stringstream ss; // Daten sind little-endian in dataBuffer ss << *((DWORD*)dataBuffer); if (dwSizeData >= sizeof(DWORD)) { ss << *((DWORD*)dataBuffer.get()); cvalue = ss.str(); } else { continue; } } else { continue; // Andere Typen ignorieren } // Füge den Wert in das Config-Objekt ein Config::ConfigData* ckey = conf->setKey(cname); conf->setValue(ckey, 0, cvalue); } } delete[] valueNameBuffer; delete[] dataBuffer; } // --- 3. Subkeys (Unterschlüssel) rekursiv laden (z.B. HTTP unter /BLOGI) --- // --- 3. Subkeys (Unterschlüssel) rekursiv laden --- if (dwSubKeys > 0) { char* subKeyNameBuffer = new char[dwMaxSubKeyLen + 1]; DWORD maxSubKeySize = dwMaxSubKeyLen > 0 ? dwMaxSubKeyLen + 1 : 1; std::unique_ptr<char[]> subKeyNameBuffer(new char[maxSubKeySize]); HKEY hSubKey; for (DWORD i = 0; i < dwSubKeys; ++i) { DWORD dwSizeSubKeyName = dwMaxSubKeyLen + 1; DWORD dwSizeSubKeyName = maxSubKeySize; lRes = RegEnumKeyExA( hKey, i, subKeyNameBuffer, &dwSizeSubKeyName, subKeyNameBuffer.get(), &dwSizeSubKeyName, NULL, NULL, NULL, NULL ); if (lRes == ERROR_SUCCESS) { // Öffne den Subkey lRes = RegOpenKeyExA( hKey, subKeyNameBuffer, 0, KEY_READ, &hSubKey hKey, subKeyNameBuffer.get(), 0, KEY_READ, &hSubKey ); if (lRes == ERROR_SUCCESS) { // Erzeuge den neuen Konfigurationspfad std::string nextConfigPath = currentConfigPath + "/" + std::string(subKeyNameBuffer); std::string nextConfigPath = currentConfigPath + "/" + std::string(subKeyNameBuffer.get()); // Rekursiver Aufruf loadKeyRecursiveA(conf, hSubKey, nextConfigPath); Loading @@ -180,7 +185,6 @@ namespace confplus { } } } delete[] subKeyNameBuffer; } } Loading @@ -204,53 +208,117 @@ namespace confplus { return "Jan Koester"; } // Hilfsfunktion zum Aufteilen des Pfades in Schlüssel und Wertnamen /** * @brief Splittet den Config-Pfad (/Abschnitt/Key) in den Registry Subkey-Pfad (Abschnitt\Key) * und den letzten Teil als Value-Namen. * @param configPath Der Pfad aus dem Config-Objekt (z.B. "/HTTP/PORT" oder "/DOMAIN/NAME"). * @param registryKeyPath [out] Der Pfad für RegCreateKeyEx relativ zum Hauptschlüssel (z.B. "HTTP" oder "DOMAIN"). * @param valueName [out] Der Name für RegSetValueExA (z.B. "PORT" oder "NAME"). * @brief Traversiert die ConfigData-Struktur rekursiv und speichert die Werte. */ void splitConfigPath(const std::string& configPath, std::string& registryKeyPath, std::string& valueName) { // Entferne den führenden '/' std::string path = configPath.length() > 0 && configPath[0] == '/' ? configPath.substr(1) : configPath; void Registry::saveKeyRecursive(HKEY hRootKey, std::string currentPath,const Config::ConfigData* currentData, const Config *conf) { // Finde den letzten '/' size_t last_slash = path.rfind('/'); // Iteriere über die 'nextData'-Kette auf der aktuellen Hierarchie-Ebene for (const Config::ConfigData* key = currentData; key != nullptr; key = key->next()) { if (last_slash == std::string::npos) { // Fall 1: Pfad ist nur der Wertname (z.B. "TEMPLATE") registryKeyPath = ""; valueName = path; // ANNAHME: key->Key enthält den lokalen Schlüsselnamen (z.B. "Datenbank", "Port") std::string localKeyName = key->getKey(); if (localKeyName.empty() && !key->childs()) { continue; } std::string subKeyPath = currentPath; std::string valueName = localKeyName; if (key->childs()) { // Sektion/Subkey if (!subKeyPath.empty()) { subKeyPath += "\\"; } subKeyPath += localKeyName; } else { // Fall 2: Pfad enthält Subkeys (z.B. "HTTP/PORT") // Registry Key Path ist alles vor dem letzten Slash registryKeyPath = path.substr(0, last_slash); // Value Name ist alles nach dem letzten Slash valueName = path.substr(last_slash + 1); // Wert if (!subKeyPath.empty()) { subKeyPath += "\\"; } subKeyPath += localKeyName; // Ersetze '/' durch '\' für die Registry-API std::replace(registryKeyPath.begin(), registryKeyPath.end(), '/', '\\'); std::string tempPath; splitConfigPath(subKeyPath, tempPath, valueName); subKeyPath = tempPath; } HKEY hSubKey; LONG lRes = RegCreateKeyExA(hRootKey, subKeyPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSubKey, NULL); if (lRes == ERROR_SUCCESS) { size_t elements = key->getElements(); for (size_t pos = 0; pos < elements; ++pos) { std::string cvalue = conf->getValue(key, pos); DWORD dwType = REG_SZ; std::string currentRegValueName = valueName; if (elements > 1) { currentRegValueName = (valueName.empty() ? "" : valueName + "_") + std::to_string(pos); } else if (valueName.empty()) { currentRegValueName = ""; // (Standardwert) } if (isInteger(cvalue)) { dwType = REG_DWORD; try { DWORD dwValue = std::stoul(cvalue); lRes = RegSetValueExA(hSubKey, currentRegValueName.c_str(), 0, dwType, (const BYTE*)&dwValue, sizeof(dwValue)); } catch (const std::exception&) { dwType = REG_SZ; lRes = RegSetValueExA(hSubKey, currentRegValueName.c_str(), 0, dwType, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); } } else { lRes = RegSetValueExA(hSubKey, currentRegValueName.c_str(), 0, dwType, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); } if (lRes != ERROR_SUCCESS) { std::cerr << "Failed to set registry value for: " << subKeyPath << "\\" << currentRegValueName << std::endl; } } // Schließe den Schlüssel, wenn es nur ein Wert war if (!key->childs() ) { RegCloseKey(hSubKey); } } else { std::cerr << "Failed to create subkey: " << subKeyPath << std::endl; } // Rekursiver Aufruf für Child-Knoten if (key->childs()) { std::string nextPath = subKeyPath; if (lRes == ERROR_SUCCESS) { saveKeyRecursive(hRootKey, nextPath, key->getChild(), conf); RegCloseKey(hSubKey); // Schließe nach der Rekursion } } } } /** * @brief Speichert die Konfiguration in der Windows Registry. */ void Registry::saveConfig(const char *path, const Config *conf){ // Öffne/Erstelle den Hauptschlüssel (z.B. "SOFTWARE\Blogi") HKEY hRootKey; DWORD dwDisposition; // Der 'path' ist der Basispfad (z.B. "SOFTWARE\Blogi") // Öffne/Erstelle den Hauptschlüssel LONG lRes = RegCreateKeyExA( REGISTRY_ROOT_KEY, path, REGISTRY_ROOT_KEY, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, KEY_ALL_ACCESS, NULL, &hRootKey, &dwDisposition ); Loading @@ -259,39 +327,10 @@ namespace confplus { throw e[ConfException::Error] << "Failed to create/open root registry key: " << path; } // --- TODO: Hier die Iterationslogik über conf->getAllKeys() implementieren --- /* for (const auto& key : conf->getAllKeys()) { std::string configPath = key->getPath(); // z.B. "/HTTP/PORT" std::string cvalue = conf->getValue(key, 0); // Hole den String-Wert std::string subKeyPath; std::string valueName; splitConfigPath(configPath, subKeyPath, valueName); // Temporäres Handle für den Subkey (z.B. "HTTP") HKEY hSubKey; // Erstellt/Öffnet den Subkey relativ zum Root-Key lRes = RegCreateKeyExA(hRootKey, subKeyPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSubKey, NULL); if (lRes == ERROR_SUCCESS) { // Konvertiere den Wert (Hier ist eine einfache String-Speicherung) // Die Unterscheidung zwischen REG_SZ und REG_DWORD müsste basierend auf dem // tatsächlichen Typ des Werts im Config-Objekt erfolgen. // Beispiel: Speichere alles als String (REG_SZ) lRes = RegSetValueExA(hSubKey, valueName.c_str(), 0, REG_SZ, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); RegCloseKey(hSubKey); } else { std::cerr << "Failed to create subkey: " << subKeyPath << std::endl; // Starte die rekursive Traversierung if (conf->firstData) { saveKeyRecursive(hRootKey, "", conf->first(), conf); } } */ // --- ENDE TODO --- RegCloseKey(hRootKey); } Loading @@ -302,9 +341,9 @@ namespace confplus { void Registry::loadConfig(const char* path, Config* conf) { HKEY hKey; // Öffne den Hauptschlüssel (z.B. "SOFTWARE\Blogi") // Öffne den Hauptschlüssel LONG lRes = RegOpenKeyExA( REGISTRY_ROOT_KEY, // Angenommen HKEY_CURRENT_USER oder HKEY_LOCAL_MACHINE REGISTRY_ROOT_KEY, path, 0, KEY_READ, Loading @@ -316,7 +355,7 @@ namespace confplus { return; } // Starte die rekursive Ladefunktion. Startpfad im Config-Objekt ist "" (wird zu /) // Starte die rekursive Ladefunktion. loadKeyRecursiveA(conf, hKey, ""); RegCloseKey(hKey); Loading backends/regedit/regedit.h +12 −5 Original line number Diff line number Diff line Loading @@ -30,6 +30,10 @@ #include "conf.h" #include "backend.h" // Wird für HKEY benötigt, um die private Methode zu deklarieren #define WIN32_LEAN_AND_MEAN #include <windows.h> namespace confplus { class Config; // Forward-Deklaration Loading @@ -49,6 +53,9 @@ namespace confplus { Registry(); virtual ~Registry(); private: // Rekursive Hilfsfunktion zur Speicherung der Config-Datenstruktur void saveKeyRecursive(HKEY hRootKey, std::string currentPath,const Config::ConfigData* currentData, const Config *conf); }; } Loading src/conf.cpp +21 −1 Original line number Diff line number Diff line Loading @@ -157,6 +157,22 @@ confplus::Config::ConfigData::~ConfigData(){ } const confplus::Config::ConfigData* confplus::Config::ConfigData::next() const{ return nextData.get(); } const std::string& confplus::Config::ConfigData::getKey() const{ return Key; } const bool confplus::Config::ConfigData::childs() const{ return haveChild; } const confplus::Config::ConfigData* confplus::Config::ConfigData::getChild() const{ return Child.get(); } size_t confplus::Config::ConfigData::getElements() const{ return Elements; } Loading Loading @@ -295,6 +311,10 @@ const char* confplus::Config::getAuthor(){ return _currApi->getAuthor(); } const confplus::Config::ConfigData* confplus::Config::first() const{ return firstData.get(); } void confplus::Config::saveConfig(const char *path){ _currApi->saveConfig(path,this); } Loading @@ -306,7 +326,7 @@ size_t confplus::Config::getElements(confplus::Config::ConfigData* key) const{ return key->Elements; } const std::string &confplus::Config::getValue(confplus::Config::ConfigData* key, size_t pos) const{ const std::string &confplus::Config::getValue(const confplus::Config::ConfigData* key, size_t pos) const{ if (!key) { ConfException err; err[ConfException::Error] << "Key not found" << pos; Loading src/conf.h +9 −2 Original line number Diff line number Diff line Loading @@ -61,9 +61,14 @@ namespace confplus { public: ~ConfigData(); ConfigData(); private: const ConfigData *next() const; const std::string &getKey() const; const bool childs() const; const ConfigData *getChild() const; size_t getElements() const; private: std::string Key; size_t Elements; Loading @@ -90,7 +95,7 @@ namespace confplus { void setValue(ConfigData *key,size_t pos,const std::string &value); void setIntValue(ConfigData *key,size_t pos,int value); const std::string &getValue(ConfigData *key,size_t pos) const; const std::string &getValue(const ConfigData *key,size_t pos) const; int getIntValue(ConfigData *key,size_t pos) const; std::unique_ptr<ConfigData>firstData=nullptr; Loading @@ -99,6 +104,8 @@ namespace confplus { const char* getVersion(); const char* getAuthor(); const ConfigData* first() const; void saveConfig(const char *path); private: BackendApi *_currApi; Loading Loading
backends/regedit/regedit.cpp +177 −138 Original line number Diff line number Diff line Loading @@ -32,61 +32,57 @@ #include <iostream> #include <string> #include <sstream> #include <algorithm> // Für std::replace #include <stdexcept> #include <memory> // Für std::unique_ptr // Spezifische Windows API Includes #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winreg.h> namespace confplus { /******************************************************************************* * Copyright (c) 2025, Jan Koester jan.koester@gmx.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ // Konfigurierbare Basis-HKEY. HKEY REGISTRY_ROOT_KEY = HKEY_CURRENT_USER; #include "regedit.h" #include "exception.h" // Angenommen: Hier ist ConfException definiert // ------------------------------------------------------------------------- // HILFSFUNKTIONEN // ------------------------------------------------------------------------- #include <iostream> #include <string> #include <sstream> #include <stdexcept> #include <algorithm> /** * @brief Splittet den Config-Pfad (/Abschnitt/Key) in den Registry Subkey-Pfad (Abschnitt\Key) * und den letzten Teil als Value-Namen. */ void splitConfigPath(const std::string& configPath, std::string& registryKeyPath, std::string& valueName) { // Entferne den führenden '/' std::string path = configPath.length() > 0 && configPath[0] == '/' ? configPath.substr(1) : configPath; // Spezifische Windows API Includes #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winreg.h> // Finde den letzten '/' size_t last_slash = path.rfind('/'); if (last_slash == std::string::npos) { registryKeyPath = ""; valueName = path; } else { registryKeyPath = path.substr(0, last_slash); valueName = path.substr(last_slash + 1); // Ersetze '/' durch '\' für die Registry-API std::replace(registryKeyPath.begin(), registryKeyPath.end(), '/', '\\'); } } bool isInteger(const std::string& s) { if (s.empty()) return false; std::string::const_iterator it = s.begin(); if (*it == '-' || *it == '+') it++; while (it != s.end() && std::isdigit(*it)) ++it; return it == s.end(); } namespace confplus { /** * @brief Rekursive Funktion zum Laden von Werten und Subkeys aus der Registry. * @param conf Das Config-Objekt, das gefüllt wird. * @param hKey Das Handle des aktuell geöffneten Registry-Schlüssels. * @param currentConfigPath Der aktuelle Pfad im Config-Objekt (z.B. "/HTTP"). */ void loadKeyRecursiveA(Config* conf, HKEY hKey, const std::string& currentConfigPath) { Loading @@ -101,77 +97,86 @@ namespace confplus { ); if (lRes != ERROR_SUCCESS) { // Fehler beim Abfragen ist nicht kritisch, einfach zurückkehren return; } // --- 2. Werte (Values) laden (z.B. PORT unter /HTTP) --- // --- 2. Werte (Values) laden --- if (dwValues > 0) { // Puffer allozieren (+1 für Nullterminierung) char* valueNameBuffer = new char[dwMaxValueNameLen + 1]; char* dataBuffer = new char[dwMaxValueLen + 1]; // maxNameSize und maxDataSize müssen die Nullterminierung mit einbeziehen DWORD maxNameSize = dwMaxValueNameLen > 0 ? dwMaxValueNameLen + 1 : 1; DWORD maxDataSize = dwMaxValueLen > 0 ? dwMaxValueLen + 1 : 1; // Verwendung von std::unique_ptr für automatische Speicherverwaltung std::unique_ptr<char[]> valueNameBuffer(new char[maxNameSize]); std::unique_ptr<char[]> dataBuffer(new char[maxDataSize]); DWORD dwSizeValueName, dwSizeData, dwType; for (DWORD i = 0; i < dwValues; ++i) { dwType = 0; dwSizeValueName = dwMaxValueNameLen + 1; dwSizeData = dwMaxValueLen + 1; dwSizeValueName = maxNameSize; dwSizeData = maxDataSize; lRes = RegEnumValueA( hKey, i, valueNameBuffer, &dwSizeValueName, valueNameBuffer.get(), &dwSizeValueName, NULL, &dwType, (LPBYTE)dataBuffer, &dwSizeData (LPBYTE)dataBuffer.get(), &dwSizeData ); if (lRes == ERROR_SUCCESS) { // Konstruiere den vollen Konfigurationspfad: /AktuellerPfad/ValueName std::string cname = currentConfigPath + "/" + std::string(valueNameBuffer); std::string valueNameStr = std::string(valueNameBuffer.get()); // Überspringe den '(Standardwert)', wenn benannte Werte vorhanden sind if (valueNameStr.empty() && dwValues > 1) { continue; } std::string cname = currentConfigPath + (valueNameStr.empty() ? "" : "/" + valueNameStr); std::string cvalue; if (dwType == REG_SZ) { cvalue = std::string(dataBuffer); cvalue = std::string(dataBuffer.get()); } else if (dwType == REG_DWORD) { std::stringstream ss; // Daten sind little-endian in dataBuffer ss << *((DWORD*)dataBuffer); if (dwSizeData >= sizeof(DWORD)) { ss << *((DWORD*)dataBuffer.get()); cvalue = ss.str(); } else { continue; } } else { continue; // Andere Typen ignorieren } // Füge den Wert in das Config-Objekt ein Config::ConfigData* ckey = conf->setKey(cname); conf->setValue(ckey, 0, cvalue); } } delete[] valueNameBuffer; delete[] dataBuffer; } // --- 3. Subkeys (Unterschlüssel) rekursiv laden (z.B. HTTP unter /BLOGI) --- // --- 3. Subkeys (Unterschlüssel) rekursiv laden --- if (dwSubKeys > 0) { char* subKeyNameBuffer = new char[dwMaxSubKeyLen + 1]; DWORD maxSubKeySize = dwMaxSubKeyLen > 0 ? dwMaxSubKeyLen + 1 : 1; std::unique_ptr<char[]> subKeyNameBuffer(new char[maxSubKeySize]); HKEY hSubKey; for (DWORD i = 0; i < dwSubKeys; ++i) { DWORD dwSizeSubKeyName = dwMaxSubKeyLen + 1; DWORD dwSizeSubKeyName = maxSubKeySize; lRes = RegEnumKeyExA( hKey, i, subKeyNameBuffer, &dwSizeSubKeyName, subKeyNameBuffer.get(), &dwSizeSubKeyName, NULL, NULL, NULL, NULL ); if (lRes == ERROR_SUCCESS) { // Öffne den Subkey lRes = RegOpenKeyExA( hKey, subKeyNameBuffer, 0, KEY_READ, &hSubKey hKey, subKeyNameBuffer.get(), 0, KEY_READ, &hSubKey ); if (lRes == ERROR_SUCCESS) { // Erzeuge den neuen Konfigurationspfad std::string nextConfigPath = currentConfigPath + "/" + std::string(subKeyNameBuffer); std::string nextConfigPath = currentConfigPath + "/" + std::string(subKeyNameBuffer.get()); // Rekursiver Aufruf loadKeyRecursiveA(conf, hSubKey, nextConfigPath); Loading @@ -180,7 +185,6 @@ namespace confplus { } } } delete[] subKeyNameBuffer; } } Loading @@ -204,53 +208,117 @@ namespace confplus { return "Jan Koester"; } // Hilfsfunktion zum Aufteilen des Pfades in Schlüssel und Wertnamen /** * @brief Splittet den Config-Pfad (/Abschnitt/Key) in den Registry Subkey-Pfad (Abschnitt\Key) * und den letzten Teil als Value-Namen. * @param configPath Der Pfad aus dem Config-Objekt (z.B. "/HTTP/PORT" oder "/DOMAIN/NAME"). * @param registryKeyPath [out] Der Pfad für RegCreateKeyEx relativ zum Hauptschlüssel (z.B. "HTTP" oder "DOMAIN"). * @param valueName [out] Der Name für RegSetValueExA (z.B. "PORT" oder "NAME"). * @brief Traversiert die ConfigData-Struktur rekursiv und speichert die Werte. */ void splitConfigPath(const std::string& configPath, std::string& registryKeyPath, std::string& valueName) { // Entferne den führenden '/' std::string path = configPath.length() > 0 && configPath[0] == '/' ? configPath.substr(1) : configPath; void Registry::saveKeyRecursive(HKEY hRootKey, std::string currentPath,const Config::ConfigData* currentData, const Config *conf) { // Finde den letzten '/' size_t last_slash = path.rfind('/'); // Iteriere über die 'nextData'-Kette auf der aktuellen Hierarchie-Ebene for (const Config::ConfigData* key = currentData; key != nullptr; key = key->next()) { if (last_slash == std::string::npos) { // Fall 1: Pfad ist nur der Wertname (z.B. "TEMPLATE") registryKeyPath = ""; valueName = path; // ANNAHME: key->Key enthält den lokalen Schlüsselnamen (z.B. "Datenbank", "Port") std::string localKeyName = key->getKey(); if (localKeyName.empty() && !key->childs()) { continue; } std::string subKeyPath = currentPath; std::string valueName = localKeyName; if (key->childs()) { // Sektion/Subkey if (!subKeyPath.empty()) { subKeyPath += "\\"; } subKeyPath += localKeyName; } else { // Fall 2: Pfad enthält Subkeys (z.B. "HTTP/PORT") // Registry Key Path ist alles vor dem letzten Slash registryKeyPath = path.substr(0, last_slash); // Value Name ist alles nach dem letzten Slash valueName = path.substr(last_slash + 1); // Wert if (!subKeyPath.empty()) { subKeyPath += "\\"; } subKeyPath += localKeyName; // Ersetze '/' durch '\' für die Registry-API std::replace(registryKeyPath.begin(), registryKeyPath.end(), '/', '\\'); std::string tempPath; splitConfigPath(subKeyPath, tempPath, valueName); subKeyPath = tempPath; } HKEY hSubKey; LONG lRes = RegCreateKeyExA(hRootKey, subKeyPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSubKey, NULL); if (lRes == ERROR_SUCCESS) { size_t elements = key->getElements(); for (size_t pos = 0; pos < elements; ++pos) { std::string cvalue = conf->getValue(key, pos); DWORD dwType = REG_SZ; std::string currentRegValueName = valueName; if (elements > 1) { currentRegValueName = (valueName.empty() ? "" : valueName + "_") + std::to_string(pos); } else if (valueName.empty()) { currentRegValueName = ""; // (Standardwert) } if (isInteger(cvalue)) { dwType = REG_DWORD; try { DWORD dwValue = std::stoul(cvalue); lRes = RegSetValueExA(hSubKey, currentRegValueName.c_str(), 0, dwType, (const BYTE*)&dwValue, sizeof(dwValue)); } catch (const std::exception&) { dwType = REG_SZ; lRes = RegSetValueExA(hSubKey, currentRegValueName.c_str(), 0, dwType, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); } } else { lRes = RegSetValueExA(hSubKey, currentRegValueName.c_str(), 0, dwType, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); } if (lRes != ERROR_SUCCESS) { std::cerr << "Failed to set registry value for: " << subKeyPath << "\\" << currentRegValueName << std::endl; } } // Schließe den Schlüssel, wenn es nur ein Wert war if (!key->childs() ) { RegCloseKey(hSubKey); } } else { std::cerr << "Failed to create subkey: " << subKeyPath << std::endl; } // Rekursiver Aufruf für Child-Knoten if (key->childs()) { std::string nextPath = subKeyPath; if (lRes == ERROR_SUCCESS) { saveKeyRecursive(hRootKey, nextPath, key->getChild(), conf); RegCloseKey(hSubKey); // Schließe nach der Rekursion } } } } /** * @brief Speichert die Konfiguration in der Windows Registry. */ void Registry::saveConfig(const char *path, const Config *conf){ // Öffne/Erstelle den Hauptschlüssel (z.B. "SOFTWARE\Blogi") HKEY hRootKey; DWORD dwDisposition; // Der 'path' ist der Basispfad (z.B. "SOFTWARE\Blogi") // Öffne/Erstelle den Hauptschlüssel LONG lRes = RegCreateKeyExA( REGISTRY_ROOT_KEY, path, REGISTRY_ROOT_KEY, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, KEY_ALL_ACCESS, NULL, &hRootKey, &dwDisposition ); Loading @@ -259,39 +327,10 @@ namespace confplus { throw e[ConfException::Error] << "Failed to create/open root registry key: " << path; } // --- TODO: Hier die Iterationslogik über conf->getAllKeys() implementieren --- /* for (const auto& key : conf->getAllKeys()) { std::string configPath = key->getPath(); // z.B. "/HTTP/PORT" std::string cvalue = conf->getValue(key, 0); // Hole den String-Wert std::string subKeyPath; std::string valueName; splitConfigPath(configPath, subKeyPath, valueName); // Temporäres Handle für den Subkey (z.B. "HTTP") HKEY hSubKey; // Erstellt/Öffnet den Subkey relativ zum Root-Key lRes = RegCreateKeyExA(hRootKey, subKeyPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSubKey, NULL); if (lRes == ERROR_SUCCESS) { // Konvertiere den Wert (Hier ist eine einfache String-Speicherung) // Die Unterscheidung zwischen REG_SZ und REG_DWORD müsste basierend auf dem // tatsächlichen Typ des Werts im Config-Objekt erfolgen. // Beispiel: Speichere alles als String (REG_SZ) lRes = RegSetValueExA(hSubKey, valueName.c_str(), 0, REG_SZ, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); RegCloseKey(hSubKey); } else { std::cerr << "Failed to create subkey: " << subKeyPath << std::endl; // Starte die rekursive Traversierung if (conf->firstData) { saveKeyRecursive(hRootKey, "", conf->first(), conf); } } */ // --- ENDE TODO --- RegCloseKey(hRootKey); } Loading @@ -302,9 +341,9 @@ namespace confplus { void Registry::loadConfig(const char* path, Config* conf) { HKEY hKey; // Öffne den Hauptschlüssel (z.B. "SOFTWARE\Blogi") // Öffne den Hauptschlüssel LONG lRes = RegOpenKeyExA( REGISTRY_ROOT_KEY, // Angenommen HKEY_CURRENT_USER oder HKEY_LOCAL_MACHINE REGISTRY_ROOT_KEY, path, 0, KEY_READ, Loading @@ -316,7 +355,7 @@ namespace confplus { return; } // Starte die rekursive Ladefunktion. Startpfad im Config-Objekt ist "" (wird zu /) // Starte die rekursive Ladefunktion. loadKeyRecursiveA(conf, hKey, ""); RegCloseKey(hKey); Loading
backends/regedit/regedit.h +12 −5 Original line number Diff line number Diff line Loading @@ -30,6 +30,10 @@ #include "conf.h" #include "backend.h" // Wird für HKEY benötigt, um die private Methode zu deklarieren #define WIN32_LEAN_AND_MEAN #include <windows.h> namespace confplus { class Config; // Forward-Deklaration Loading @@ -49,6 +53,9 @@ namespace confplus { Registry(); virtual ~Registry(); private: // Rekursive Hilfsfunktion zur Speicherung der Config-Datenstruktur void saveKeyRecursive(HKEY hRootKey, std::string currentPath,const Config::ConfigData* currentData, const Config *conf); }; } Loading
src/conf.cpp +21 −1 Original line number Diff line number Diff line Loading @@ -157,6 +157,22 @@ confplus::Config::ConfigData::~ConfigData(){ } const confplus::Config::ConfigData* confplus::Config::ConfigData::next() const{ return nextData.get(); } const std::string& confplus::Config::ConfigData::getKey() const{ return Key; } const bool confplus::Config::ConfigData::childs() const{ return haveChild; } const confplus::Config::ConfigData* confplus::Config::ConfigData::getChild() const{ return Child.get(); } size_t confplus::Config::ConfigData::getElements() const{ return Elements; } Loading Loading @@ -295,6 +311,10 @@ const char* confplus::Config::getAuthor(){ return _currApi->getAuthor(); } const confplus::Config::ConfigData* confplus::Config::first() const{ return firstData.get(); } void confplus::Config::saveConfig(const char *path){ _currApi->saveConfig(path,this); } Loading @@ -306,7 +326,7 @@ size_t confplus::Config::getElements(confplus::Config::ConfigData* key) const{ return key->Elements; } const std::string &confplus::Config::getValue(confplus::Config::ConfigData* key, size_t pos) const{ const std::string &confplus::Config::getValue(const confplus::Config::ConfigData* key, size_t pos) const{ if (!key) { ConfException err; err[ConfException::Error] << "Key not found" << pos; Loading
src/conf.h +9 −2 Original line number Diff line number Diff line Loading @@ -61,9 +61,14 @@ namespace confplus { public: ~ConfigData(); ConfigData(); private: const ConfigData *next() const; const std::string &getKey() const; const bool childs() const; const ConfigData *getChild() const; size_t getElements() const; private: std::string Key; size_t Elements; Loading @@ -90,7 +95,7 @@ namespace confplus { void setValue(ConfigData *key,size_t pos,const std::string &value); void setIntValue(ConfigData *key,size_t pos,int value); const std::string &getValue(ConfigData *key,size_t pos) const; const std::string &getValue(const ConfigData *key,size_t pos) const; int getIntValue(ConfigData *key,size_t pos) const; std::unique_ptr<ConfigData>firstData=nullptr; Loading @@ -99,6 +104,8 @@ namespace confplus { const char* getVersion(); const char* getAuthor(); const ConfigData* first() const; void saveConfig(const char *path); private: BackendApi *_currApi; Loading