Initial commit

This commit is contained in:
Niklas080208
2026-02-11 20:33:01 +01:00
commit 617265f004
145 changed files with 45252 additions and 0 deletions

310
src/ini_handler.cpp Normal file
View File

@@ -0,0 +1,310 @@
/*
SWR INI Tool - Switchroot INI Configuration Editor
Copyright (C) 2026 Switchroot
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
#include "ini_handler.h"
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstring>
static std::string trim(const std::string& str)
{
size_t first = str.find_first_not_of(" \t\r\n");
if (first == std::string::npos)
return "";
size_t last = str.find_last_not_of(" \t\r\n");
return str.substr(first, last - first + 1);
}
static std::string toLower(const std::string& str)
{
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
return result;
}
IniHandler::IniHandler() : loaded(false)
{
}
bool IniHandler::load(const std::string& path)
{
this->filePath = path;
this->lines.clear();
this->loaded = false;
std::ifstream file(path);
if (!file.is_open())
return false;
std::string currentSection;
std::string rawLine;
while (std::getline(file, rawLine))
{
Line line;
line.raw = rawLine;
std::string trimmed = trim(rawLine);
if (trimmed.empty())
{
line.type = Line::BLANK;
}
else if (trimmed[0] == '#' || trimmed[0] == ';')
{
line.type = Line::COMMENT;
}
else if (trimmed[0] == '[' && trimmed.back() == ']')
{
line.type = Line::SECTION;
line.section = trim(trimmed.substr(1, trimmed.size() - 2));
currentSection = line.section;
}
else
{
size_t eqPos = trimmed.find('=');
if (eqPos != std::string::npos)
{
line.type = Line::KEY_VALUE;
line.section = currentSection;
line.key = trim(trimmed.substr(0, eqPos));
line.value = trim(trimmed.substr(eqPos + 1));
}
else
{
line.type = Line::COMMENT; // treat unparseable lines as comments
}
}
this->lines.push_back(line);
}
file.close();
this->loaded = true;
return true;
}
bool IniHandler::save()
{
return save(this->filePath);
}
bool IniHandler::save(const std::string& path)
{
std::ofstream file(path);
if (!file.is_open())
return false;
for (size_t i = 0; i < this->lines.size(); i++)
{
const Line& line = this->lines[i];
if (line.type == Line::KEY_VALUE)
{
file << line.key << "=" << line.value;
}
else
{
file << line.raw;
}
if (i < this->lines.size() - 1)
file << "\n";
}
file.close();
return true;
}
std::string IniHandler::get(const std::string& section, const std::string& key, const std::string& defaultValue) const
{
int idx = findLine(section, key);
if (idx >= 0)
return this->lines[idx].value;
return defaultValue;
}
int IniHandler::getInt(const std::string& section, const std::string& key, int defaultValue) const
{
std::string val = get(section, key, "");
if (val.empty())
return defaultValue;
try
{
return std::stoi(val);
}
catch (...)
{
return defaultValue;
}
}
bool IniHandler::getBool(const std::string& section, const std::string& key, bool defaultValue) const
{
return getInt(section, key, defaultValue ? 1 : 0) != 0;
}
void IniHandler::set(const std::string& section, const std::string& key, const std::string& value)
{
int idx = findLine(section, key);
if (idx >= 0)
{
this->lines[idx].value = value;
}
else
{
// Key doesn't exist - add it at the end of the section
int sectionEnd = findSectionEnd(section);
if (sectionEnd < 0)
{
// Section doesn't exist - create it
Line sectionLine;
sectionLine.type = Line::SECTION;
sectionLine.section = section;
sectionLine.raw = "[" + section + "]";
Line blankLine;
blankLine.type = Line::BLANK;
blankLine.raw = "";
Line kvLine;
kvLine.type = Line::KEY_VALUE;
kvLine.section = section;
kvLine.key = key;
kvLine.value = value;
this->lines.push_back(blankLine);
this->lines.push_back(sectionLine);
this->lines.push_back(kvLine);
}
else
{
Line kvLine;
kvLine.type = Line::KEY_VALUE;
kvLine.section = section;
kvLine.key = key;
kvLine.value = value;
this->lines.insert(this->lines.begin() + sectionEnd, kvLine);
}
}
}
void IniHandler::setInt(const std::string& section, const std::string& key, int value)
{
set(section, key, std::to_string(value));
}
void IniHandler::setBool(const std::string& section, const std::string& key, bool value)
{
setInt(section, key, value ? 1 : 0);
}
bool IniHandler::hasSection(const std::string& section) const
{
for (const Line& line : this->lines)
{
if (line.type == Line::SECTION && toLower(line.section) == toLower(section))
return true;
}
return false;
}
bool IniHandler::hasKey(const std::string& section, const std::string& key) const
{
return findLine(section, key) >= 0;
}
std::vector<std::string> IniHandler::getSections() const
{
std::vector<std::string> sections;
for (const Line& line : this->lines)
{
if (line.type == Line::SECTION)
sections.push_back(line.section);
}
return sections;
}
std::vector<std::pair<std::string, std::string>> IniHandler::getKeys(const std::string& section) const
{
std::vector<std::pair<std::string, std::string>> keys;
for (const Line& line : this->lines)
{
if (line.type == Line::KEY_VALUE && toLower(line.section) == toLower(section))
keys.push_back({line.key, line.value});
}
return keys;
}
std::string IniHandler::findOsSection() const
{
for (const Line& line : this->lines)
{
if (line.type == Line::SECTION && toLower(line.section) != "config")
return line.section;
}
return "";
}
int IniHandler::findLine(const std::string& section, const std::string& key) const
{
std::string sectionLower = toLower(section);
std::string keyLower = toLower(key);
for (size_t i = 0; i < this->lines.size(); i++)
{
const Line& line = this->lines[i];
if (line.type == Line::KEY_VALUE &&
toLower(line.section) == sectionLower &&
toLower(line.key) == keyLower)
{
return (int)i;
}
}
return -1;
}
int IniHandler::findSectionEnd(const std::string& section) const
{
std::string sectionLower = toLower(section);
bool inSection = false;
int lastLine = -1;
for (size_t i = 0; i < this->lines.size(); i++)
{
const Line& line = this->lines[i];
if (line.type == Line::SECTION)
{
if (toLower(line.section) == sectionLower)
{
inSection = true;
lastLine = (int)i + 1;
}
else if (inSection)
{
return lastLine;
}
}
else if (inSection && line.type != Line::BLANK)
{
lastLine = (int)i + 1;
}
}
if (inSection)
return lastLine;
return -1;
}