mirror of
https://github.com/hyprwm/hyprcursor.git
synced 2024-12-22 10:19:48 +01:00
178717746d
* Validate cursor file names * Propagate errors from parsing HL cursor * Validate cursor directory names
182 lines
5.5 KiB
C++
182 lines
5.5 KiB
C++
#include "meta.hpp"
|
|
|
|
#include <hyprlang.hpp>
|
|
#include <toml++/toml.hpp>
|
|
#include <filesystem>
|
|
#include <regex>
|
|
|
|
#include "VarList.hpp"
|
|
|
|
CMeta* currentMeta = nullptr;
|
|
|
|
CMeta::CMeta(const std::string& rawdata_, bool hyprlang_ /* false for toml */, bool dataIsPath) : rawdata(rawdata_), hyprlang(hyprlang_), dataPath(dataIsPath) {
|
|
if (!dataIsPath)
|
|
return;
|
|
|
|
rawdata = "";
|
|
|
|
try {
|
|
if (std::filesystem::exists(rawdata_ + ".hl")) {
|
|
rawdata = rawdata_ + ".hl";
|
|
hyprlang = true;
|
|
return;
|
|
}
|
|
|
|
if (std::filesystem::exists(rawdata_ + ".toml")) {
|
|
rawdata = rawdata_ + ".toml";
|
|
hyprlang = false;
|
|
return;
|
|
}
|
|
} catch (...) {}
|
|
}
|
|
|
|
std::optional<std::string> CMeta::parse() {
|
|
if (rawdata.empty())
|
|
return "Invalid meta (missing?)";
|
|
|
|
std::optional<std::string> res;
|
|
|
|
currentMeta = this;
|
|
|
|
if (hyprlang)
|
|
res = parseHL();
|
|
else
|
|
res = parseTOML();
|
|
|
|
currentMeta = nullptr;
|
|
|
|
return res;
|
|
}
|
|
|
|
static std::string removeBeginEndSpacesTabs(std::string str) {
|
|
if (str.empty())
|
|
return str;
|
|
|
|
int countBefore = 0;
|
|
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
|
countBefore++;
|
|
}
|
|
|
|
int countAfter = 0;
|
|
while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
|
|
countAfter++;
|
|
}
|
|
|
|
str = str.substr(countBefore, str.length() - countBefore - countAfter);
|
|
|
|
return str;
|
|
}
|
|
|
|
static Hyprlang::CParseResult parseDefineSize(const char* C, const char* V) {
|
|
Hyprlang::CParseResult result;
|
|
const std::string VALUE = V;
|
|
|
|
if (!VALUE.contains(",")) {
|
|
result.setError("Invalid define_size");
|
|
return result;
|
|
}
|
|
|
|
auto LHS = removeBeginEndSpacesTabs(VALUE.substr(0, VALUE.find_first_of(",")));
|
|
auto RHS = removeBeginEndSpacesTabs(VALUE.substr(VALUE.find_first_of(",") + 1));
|
|
auto DELAY = 0;
|
|
|
|
CMeta::SDefinedSize size;
|
|
|
|
if (RHS.contains(",")) {
|
|
const auto LL = removeBeginEndSpacesTabs(RHS.substr(0, RHS.find(",")));
|
|
const auto RR = removeBeginEndSpacesTabs(RHS.substr(RHS.find(",") + 1));
|
|
|
|
try {
|
|
size.delayMs = std::stoull(RR);
|
|
} catch (std::exception& e) {
|
|
result.setError(e.what());
|
|
return result;
|
|
}
|
|
|
|
RHS = LL;
|
|
}
|
|
|
|
if (!std::regex_match(RHS, std::regex("^[A-Za-z0-9_\\-\\.]+$"))) {
|
|
result.setError("Invalid cursor file name, characters must be within [A-Za-z0-9_\\-\\.] (if this seems like a mistake, check for invisible characters)");
|
|
return result;
|
|
}
|
|
|
|
size.file = RHS;
|
|
|
|
if (!size.file.ends_with(".svg")) {
|
|
try {
|
|
size.size = std::stoull(LHS);
|
|
} catch (std::exception& e) {
|
|
result.setError(e.what());
|
|
return result;
|
|
}
|
|
} else
|
|
size.size = 0;
|
|
|
|
currentMeta->parsedData.definedSizes.push_back(size);
|
|
|
|
return result;
|
|
}
|
|
|
|
static Hyprlang::CParseResult parseOverride(const char* C, const char* V) {
|
|
Hyprlang::CParseResult result;
|
|
const std::string VALUE = V;
|
|
|
|
currentMeta->parsedData.overrides.push_back(VALUE);
|
|
|
|
return result;
|
|
}
|
|
|
|
std::optional<std::string> CMeta::parseHL() {
|
|
std::unique_ptr<Hyprlang::CConfig> meta;
|
|
|
|
try {
|
|
meta = std::make_unique<Hyprlang::CConfig>(rawdata.c_str(), Hyprlang::SConfigOptions{.pathIsStream = !dataPath});
|
|
meta->addConfigValue("hotspot_x", Hyprlang::FLOAT{0.F});
|
|
meta->addConfigValue("hotspot_y", Hyprlang::FLOAT{0.F});
|
|
meta->addConfigValue("resize_algorithm", Hyprlang::STRING{"nearest"});
|
|
meta->registerHandler(::parseDefineSize, "define_size", {.allowFlags = false});
|
|
meta->registerHandler(::parseOverride, "define_override", {.allowFlags = false});
|
|
meta->commence();
|
|
const auto RESULT = meta->parse();
|
|
if (RESULT.error)
|
|
return RESULT.getError();
|
|
} catch (const char* err) { return "failed parsing meta: " + std::string{err}; }
|
|
|
|
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
|
|
parsedData.hotspotY = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_y"));
|
|
parsedData.resizeAlgo = std::any_cast<Hyprlang::STRING>(meta->getConfigValue("resize_algorithm"));
|
|
|
|
return {};
|
|
}
|
|
|
|
std::optional<std::string> CMeta::parseTOML() {
|
|
try {
|
|
auto MANIFEST = dataPath ? toml::parse_file(rawdata) : toml::parse(rawdata);
|
|
|
|
parsedData.hotspotX = MANIFEST["General"]["hotspot_x"].value_or(0.f);
|
|
parsedData.hotspotY = MANIFEST["General"]["hotspot_y"].value_or(0.f);
|
|
|
|
const std::string OVERRIDES = MANIFEST["General"]["define_override"].value_or("");
|
|
const std::string SIZES = MANIFEST["General"]["define_size"].value_or("");
|
|
|
|
//
|
|
CVarList OVERRIDESLIST(OVERRIDES, 0, ';', true);
|
|
for (auto& o : OVERRIDESLIST) {
|
|
const auto RESULT = ::parseOverride("define_override", o.c_str());
|
|
if (RESULT.error)
|
|
throw;
|
|
}
|
|
|
|
CVarList SIZESLIST(SIZES, 0, ';', true);
|
|
for (auto& s : SIZESLIST) {
|
|
const auto RESULT = ::parseDefineSize("define_size", s.c_str());
|
|
if (RESULT.error)
|
|
throw;
|
|
}
|
|
|
|
parsedData.resizeAlgo = MANIFEST["General"]["resize_algorithm"].value_or("");
|
|
} catch (std::exception& e) { return std::string{"Failed parsing toml: "} + e.what(); }
|
|
|
|
return {};
|
|
}
|