#include "fgc/CameraMode.h" #include #include #include #include extern "C" { #include "ini.h" } namespace fs = std::filesystem; namespace fgc { namespace { // inih callback. Unlike Config.cpp's handler this APPENDS rather than writing a // map: mode files depend on file order and on repeated keys (see CameraMode). int modeHandler(void* user, const char* section, const char* name, const char* value) { auto* m = static_cast(user); const std::string sec = section ? section : ""; const std::string key = name ? name : ""; const std::string val = value ? value : ""; if (sec == "Camera") { m->features.emplace_back(key, val); return 1; } if (sec != "Mode") return 0; // unknown section -> parse error if (key == "description") { m->description = val; } else if (key == "settle_wait_ms" || key == "frame_timeout_ms") { int parsed = 0; try { size_t consumed = 0; parsed = std::stoi(val, &consumed); if (consumed != val.size() || parsed < 0) return 0; } catch (const std::exception&) { return 0; } (key == "settle_wait_ms" ? m->settle_wait_ms : m->frame_timeout_ms) = parsed; } else { return 0; // unknown [Mode] key -> parse error, not a silent typo } return 1; } } // namespace CameraMode loadCameraMode(const std::string& path) { CameraMode mode; mode.name = fs::path(path).stem().string(); const int rc = ini_parse(path.c_str(), modeHandler, &mode); if (rc == -1) throw std::runtime_error("Cannot open camera mode file: " + path); if (rc == -2) throw std::runtime_error("Out of memory reading camera mode file: " + path); if (rc > 0) throw std::runtime_error("Camera mode file '" + path + "' line " + std::to_string(rc) + ": unknown section, unknown [Mode] key, or invalid value " "(expected [Mode] description/settle_wait_ms/frame_timeout_ms, " "or a [Camera] feature)"); if (mode.features.empty()) throw std::runtime_error("Camera mode file '" + path + "' sets no [Camera] features"); return mode; } std::map loadCameraModes(const std::string& dir) { std::error_code ec; if (!fs::is_directory(dir, ec)) throw std::runtime_error("Camera mode directory not found: " + dir); // Sorted so startup logs and the UI list modes in a stable order. std::vector files; for (const auto& entry : fs::directory_iterator(dir, ec)) if (entry.is_regular_file() && entry.path().extension() == ".ini") files.push_back(entry.path()); std::sort(files.begin(), files.end()); std::map modes; for (const auto& f : files) { CameraMode m = loadCameraMode(f.string()); modes.emplace(m.name, std::move(m)); } if (modes.empty()) throw std::runtime_error("No camera modes (*.ini) in " + dir); return modes; } } // namespace fgc