Path: blob/a-new-beginning/SharedDependencies/Sources/inih/INIReader.cpp
2 views
// Read an INI file into easy-to-access name/value pairs.12// SPDX-License-Identifier: BSD-3-Clause34// Copyright (C) 2009-2025, Ben Hoyt56// inih and INIReader are released under the New BSD license (see LICENSE.txt).7// Go to the project home page for more info:8//9// https://github.com/benhoyt/inih1011#include <algorithm>12#include <cctype>13#include <cstdlib>14#include "ini.h"15#include "INIReader.h"1617using std::string;1819INIReader::INIReader(const string& filename)20{21_error = ini_parse(filename.c_str(), ValueHandler, this);22}2324INIReader::INIReader(const char *buffer, size_t buffer_size)25{26_error = ini_parse_string_length(buffer, buffer_size, ValueHandler, this);27}2829int INIReader::ParseError() const30{31return _error;32}3334string INIReader::ParseErrorMessage() const35{36// If _error is positive it means it is the line number on which a parse37// error occurred. This could be an overlong line, that ValueHandler38// indicated a user defined error, an unterminated section name, or a name39// without a value.40if (_error > 0) {41return "parse error on line " + std::to_string(_error) + "; missing ']' or '='?";42}4344// If _error is negative it is a system type error, and 0 means success.45switch (_error) {46case -2:47return "unable to allocate memory";4849case -1:50return "unable to open file";5152case 0:53return "";54}5556// This should never be reached. It probably means a new error code was57// added to the C API without updating this method.58return "unknown error " + std::to_string(_error);59}6061string INIReader::Get(const string& section, const string& name, const string& default_value) const62{63string key = MakeKey(section, name);64// Use _values.find() here instead of _values.at() to support pre C++11 compilers65return _values.count(key) ? _values.find(key)->second : default_value;66}6768string INIReader::GetString(const string& section, const string& name, const string& default_value) const69{70const string str = Get(section, name, "");71return str.empty() ? default_value : str;72}7374long INIReader::GetInteger(const string& section, const string& name, long default_value) const75{76string valstr = Get(section, name, "");77const char* value = valstr.c_str();78char* end;79// This parses "1234" (decimal) and also "0x4D2" (hex)80long n = strtol(value, &end, 0);81return end > value ? n : default_value;82}8384INI_API int64_t INIReader::GetInteger64(const string& section, const string& name, int64_t default_value) const85{86string valstr = Get(section, name, "");87const char* value = valstr.c_str();88char* end;89// This parses "1234" (decimal) and also "0x4D2" (hex)90int64_t n = strtoll(value, &end, 0);91return end > value ? n : default_value;92}9394unsigned long INIReader::GetUnsigned(const string& section, const string& name, unsigned long default_value) const95{96string valstr = Get(section, name, "");97const char* value = valstr.c_str();98char* end;99// This parses "1234" (decimal) and also "0x4D2" (hex)100unsigned long n = strtoul(value, &end, 0);101return end > value ? n : default_value;102}103104INI_API uint64_t INIReader::GetUnsigned64(const string& section, const string& name, uint64_t default_value) const105{106string valstr = Get(section, name, "");107const char* value = valstr.c_str();108char* end;109// This parses "1234" (decimal) and also "0x4D2" (hex)110uint64_t n = strtoull(value, &end, 0);111return end > value ? n : default_value;112}113114double INIReader::GetReal(const string& section, const string& name, double default_value) const115{116string valstr = Get(section, name, "");117const char* value = valstr.c_str();118char* end;119double n = strtod(value, &end);120return end > value ? n : default_value;121}122123bool INIReader::GetBoolean(const string& section, const string& name, bool default_value) const124{125string valstr = Get(section, name, "");126// Convert to lower case to make string comparisons case-insensitive127std::transform(valstr.begin(), valstr.end(), valstr.begin(),128[](const unsigned char& ch) { return static_cast<unsigned char>(::tolower(ch)); });129if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")130return true;131else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")132return false;133else134return default_value;135}136137std::vector<string> INIReader::Sections() const138{139std::set<string> sectionSet;140for (std::map<string, string>::const_iterator it = _values.begin(); it != _values.end(); ++it) {141size_t pos = it->first.find('=');142if (pos != string::npos) {143sectionSet.insert(it->first.substr(0, pos));144}145}146return std::vector<string>(sectionSet.begin(), sectionSet.end());147}148149std::vector<string> INIReader::Keys(const string& section) const150{151std::vector<string> keys;152string keyPrefix = MakeKey(section, "");153for (std::map<string, string>::const_iterator it = _values.begin(); it != _values.end(); ++it) {154if (it->first.compare(0, keyPrefix.length(), keyPrefix) == 0) {155keys.push_back(it->first.substr(keyPrefix.length()));156}157}158return keys;159}160161bool INIReader::HasSection(const string& section) const162{163const string key = MakeKey(section, "");164std::map<string, string>::const_iterator pos = _values.lower_bound(key);165if (pos == _values.end())166return false;167// Does the key at the lower_bound pos start with "section"?168return pos->first.compare(0, key.length(), key) == 0;169}170171bool INIReader::HasValue(const string& section, const string& name) const172{173string key = MakeKey(section, name);174return _values.count(key);175}176177string INIReader::MakeKey(const string& section, const string& name)178{179string key = section + "=" + name;180// Convert to lower case to make section/name lookups case-insensitive181std::transform(key.begin(), key.end(), key.begin(),182[](const unsigned char& ch) { return static_cast<unsigned char>(::tolower(ch)); });183return key;184}185186int INIReader::ValueHandler(void* user, const char* section, const char* name,187const char* value)188{189if (!name) // Happens when INI_CALL_HANDLER_ON_NEW_SECTION enabled190return 1;191INIReader* reader = static_cast<INIReader*>(user);192string key = MakeKey(section, name);193if (reader->_values[key].size() > 0)194reader->_values[key] += "\n";195reader->_values[key] += value ? value : "";196return 1;197}198199200